Compute Normals of a Mesh#
Synopsis#
Compute normals of a mesh
Results#
Output:
Index * Point * Normal
0 * [0.461602, -0.018446, -0.115989] * [0.964656, 0.0898966, -0.247704]
1 * [0.202784, 0.359481, -0.217858] * [0.398458, 0.53089, -0.747922]
2 * [-0.481417, -0.046787, 0.167623] * [-0.987132, 0.0342443, 0.1562]
3 * [-0.028388, -0.193602, -0.329748] * [-0.73488, -0.637902, -0.230287]
4 * [-0.087584, 0.116513, -0.399884] * [-0.396325, 0.718368, -0.571729]
5 * [0.310978, -0.239208, -0.176146] * [-0.256754, 0.55162, -0.793595]
6 * [-0.303314, 0.043035, -0.515252] * [-0.26465, 0.684736, -0.679041]
7 * [-0.256717, -0.39897, 0.177429] * [0.0907732, -0.987892, 0.125819]
8 * [0.393919, -0.388691, -0.207638] * [0.290631, -0.955747, -0.0456223]
9 * [-0.225987, -0.368634, -0.367823] * [0.154093, 0.365541, -0.917952]
10 * [-0.142556, -0.187471, -0.613449] * [0.902758, -0.0825592, -0.422153]
11 * [0.405923, -0.12839, -0.433595] * [0.432278, -0.901416, 0.0241831]
12 * [0.107094, 0.05873, -0.53405] * [0.452665, 0.664453, -0.594639]
13 * [0.179737, -0.358912, 0.264171] * [0.622873, -0.779647, 0.0646554]
14 * [0.270291, 0.167529, -0.267412] * [0.282452, 0.630941, -0.722588]
15 * [0.190508, -0.139941, -0.30917] * [0.642572, -0.758423, 0.109063]
16 * [-0.405901, 0.088723, -0.347001] * [-0.736406, 0.557068, -0.383904]
17 * [0.150462, -0.314033, -0.695425] * [-0.171163, -0.38232, -0.908039]
18 * [-0.134383, -0.384493, 0.060186] * [-0.0256952, -0.994633, 0.100226]
19 * [-0.333505, -0.116041, -0.567548] * [-0.847824, -0.186998, -0.496212]
20 * [-0.133643, -0.267196, -0.238155] * [0.123997, 0.550013, -0.8259]
21 * [-0.274406, 0.185852, -0.366349] * [-0.0630695, 0.682696, -0.727976]
22 * [-0.34352, -0.372556, 0.17102] * [-0.565292, -0.779407, 0.270129]
23 * [-0.468522, 0.005617, -0.307273] * [-0.945988, 0.0866878, -0.312397]
24 * [0.012837, 0.243987, -0.417788] * [-0.288839, 0.714998, -0.636671]
25 * [0.004712, 0.118755, -0.486604] * [-0.451072, 0.542366, -0.708783]
[...]
1300 * [0.429046, 0.119465, 0.002968] * [0.838127, 0.413114, -0.356201]
1301 * [-0.346539, -0.163042, 0.316913] * [-0.323662, 0.716134, 0.618381]
1302 * [-0.111388, 0.551166, -0.050984] * [-0.558618, 0.686741, -0.465115]
1303 * [0.376285, 0.211351, 0.347429] * [0.754427, -0.0746173, 0.652129]
1304 * [-0.026005, 0.583073, 0.081228] * [0.60426, 0.298334, 0.738828]
1305 * [-0.196168, -0.079437, 0.372088] * [-0.859283, 0.463078, 0.217237]
1306 * [-0.000569, 0.431162, 0.415514] * [0.683671, 0.70426, 0.191341]
Code#
C++#
#include "itkVector.h"
#include "itkQuadEdgeMesh.h"
#include "itkMeshFileReader.h"
#include "itkQuadEdgeMeshExtendedTraits.h"
#include "itkNormalQuadEdgeMeshFilter.h"
int
main(int argc, char * argv[])
{
if (argc < 2)
{
std::cerr << "Usage:" << std::endl;
std::cerr << argv[0] << "<InputFileName> <WeightType>" << std::endl;
std::cerr << "Weight type: " << std::endl;
std::cerr << " * 0: GOURAUD" << std::endl;
std::cerr << " * 1: THURMER" << std::endl;
std::cerr << " * 2: AREA" << std::endl;
return EXIT_FAILURE;
}
constexpr unsigned int Dimension = 3;
using CoordType = double;
using InputMeshType = itk::QuadEdgeMesh<CoordType, Dimension>;
using VectorType = itk::Vector<CoordType, Dimension>;
using Traits =
itk::QuadEdgeMeshExtendedTraits<VectorType, Dimension, 2, CoordType, CoordType, VectorType, bool, bool>;
using ReaderType = itk::MeshFileReader<InputMeshType>;
auto reader = ReaderType::New();
reader->SetFileName(argv[1]);
reader->Update();
using OutputMeshType = itk::QuadEdgeMesh<VectorType, Dimension, Traits>;
using NormalFilterType = itk::NormalQuadEdgeMeshFilter<InputMeshType, OutputMeshType>;
NormalFilterType::WeightEnum weight_type;
int param = std::stoi(argv[2]);
if ((param < 0) || (param > 2))
{
std::cerr << "Weight type must be either: " << std::endl;
std::cerr << " * 0: GOURAUD" << std::endl;
std::cerr << " * 1: THURMER" << std::endl;
std::cerr << " * 2: AREA" << std::endl;
return EXIT_FAILURE;
}
else
{
switch (param)
{
default:
case 0:
weight_type = itk::NormalQuadEdgeMeshFilterEnums::Weight::GOURAUD;
break;
case 1:
weight_type = itk::NormalQuadEdgeMeshFilterEnums::Weight::THURMER;
break;
case 2:
weight_type = itk::NormalQuadEdgeMeshFilterEnums::Weight::AREA;
break;
}
}
auto normals = NormalFilterType::New();
normals->SetInput(reader->GetOutput());
normals->SetWeight(weight_type);
normals->Update();
OutputMeshType::Pointer output = normals->GetOutput();
OutputMeshType::PointsContainerPointer points = output->GetPoints();
OutputMeshType::PointsContainerIterator p_it = points->Begin();
OutputMeshType::PointDataContainerPointer container = output->GetPointData();
OutputMeshType::PointDataContainerIterator d_it = container->Begin();
std::cout << "Index * Point * Normal" << std::endl;
while (p_it != points->End())
{
std::cout << p_it.Index() << " * ";
std::cout << p_it.Value() << " * ";
std::cout << d_it.Value() << std::endl;
++p_it;
++d_it;
}
return EXIT_SUCCESS;
}
Classes demonstrated#
-
template<typename TInputMesh, typename TOutputMesh>
class NormalQuadEdgeMeshFilter : public itk::QuadEdgeMeshToQuadEdgeMeshFilter<TInputMesh, TOutputMesh> Filter which computes normals to faces and vertices and store it in the output mesh. Normals to face are first computed, then normals to vertices are computed as linear combination of neighbor face normals, i.e.
The difference between each method relies in the definition of the weight that you can specify by the method SetWeight.
GOURAUD [1]
THURMER Angle of the considered triangle at the given vertex} [2]
AREA [3]
These weights are defined in the literature:
[1] Henri Gouraud. Continuous shading of curved surfaces. IEEE Transaction on Computers, 20(6):623-629, 1971
[2] Shuangshuang Jin, Robert R. Lewis, and David West. A comparison of algorithms for vertex normal computation. The Visual Computer, 21(1-2):71-82, 2005.
[3] Grit Thurmer and Charles A. Wuthrich. Computing vertex normals from polygonal facets. Journal of Graphic Tools, 3(1):43-46, 1998.
- Note
By default the weight is set to the TURMER weight.
- ITK Sphinx Examples: