/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ // Software Guide : BeginLatex // // The \doxygen{Mesh} class is extremely general and flexible, but // there is some cost to convenience. If convenience is exactly what // you need, then it is possible to get it, in exchange for some of // that flexibility, by means of the // \doxygen{AutomaticTopologyMeshSource} class. This class // automatically generates an explicit K-Complex, based on the cells // you add. It explicitly includes all boundary information, so that // the resulting mesh can be easily traversed. It merges all shared // edges, vertices, and faces, so no geometric feature appears more // than once. // // This section shows how you can use the AutomaticTopologyMeshSource to // instantiate a mesh representing a K-Complex. We will first generate the // same tetrahedron from Section~\ref{sec:MeshKComplex}, after which we will // add a hollow one to illustrate some additional features of the mesh // source. // // \index{itk::Mesh!K-Complex} // \index{itk::AutomaticTopologyMeshSource} // // Software Guide : EndLatex // Software Guide : BeginLatex // // The header files of all the cell types involved should be loaded along // with the header file of the mesh class. // // \index{itk::AutomaticTopologyMeshSource!header} // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet #include "itkTriangleCell.h" #include "itkAutomaticTopologyMeshSource.h" // Software Guide : EndCodeSnippet int main(int, char *[]) { // Software Guide : BeginLatex // // We then define the necessary types and instantiate the mesh // source. Two new types are \code{IdentifierType} and // \code{IdentifierArrayType}. Every cell in a mesh has an // identifier, whose type is determined by the mesh traits. // AutomaticTopologyMeshSource requires that the identifier // type of all vertices and cells be \code{unsigned long}, which is // already the default. However, if you created a new mesh traits // class to use string tags as identifiers, the resulting mesh // would not be compatible with \doxygen{AutomaticTopologyMeshSource}. // An \code{IdentifierArrayType} is simply an \doxygen{Array} // of \code{IdentifierType} objects. // // \index{itk::AutomaticTopologyMeshSource!IdentifierType} // \index{itk::AutomaticTopologyMeshSource!IdentifierArrayType} // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet using PixelType = float; using MeshType = itk::Mesh; using PointType = MeshType::PointType; using MeshSourceType = itk::AutomaticTopologyMeshSource; using IdentifierArrayType = MeshSourceType::IdentifierArrayType; MeshSourceType::Pointer meshSource; meshSource = MeshSourceType::New(); // Software Guide : EndCodeSnippet // Software Guide : BeginLatex // // Now let us generate the tetrahedron. The following line of code // generates all the vertices, edges, and faces, along with the // tetrahedral solid, and adds them to the mesh along with the // connectivity information. // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet meshSource->AddTetrahedron(meshSource->AddPoint(-1, -1, -1), meshSource->AddPoint(1, 1, -1), meshSource->AddPoint(1, -1, 1), meshSource->AddPoint(-1, 1, 1)); // Software Guide : EndCodeSnippet // Software Guide : BeginLatex // // The function // \code{AutomaticTopologyMeshSource::AddTetrahedron()} // takes point identifiers as parameters; the identifiers must // correspond to points that have already been added. // \code{AutomaticTopologyMeshSource::AddPoint()} returns // the appropriate identifier type for the point being added. It // first checks to see if the point is already in the mesh. If so, // it returns the ID of the point in the mesh, and if not, it // generates a new unique ID, adds the point with that ID, and // returns the ID. // // \index{itk::AutomaticTopologyMeshSource!AddPoint()} // \index{itk::AutomaticTopologyMeshSource!AddTetrahedron()} // // Actually, \code{AddTetrahedron()} behaves in the same way. If // the tetrahedron has already been added, it leaves the mesh // unchanged and returns the ID that the tetrahedron already has. // If not, it adds the tetrahedron (and all its faces, edges, and // vertices), and generates a new ID, which it returns. // // It is also possible to add all the points first, and then add a // number of cells using the point IDs directly. This approach // corresponds with the way the data is stored in many file formats // for 3D polygonal models. // // First we add the points (in this case the vertices of a larger // tetrahedron). This example also illustrates that // \code{AddPoint()} can take a single \code{PointType} as a // parameter if desired, rather than a sequence of floats. Another // possibility (not illustrated) is to pass in a C-style array. // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet PointType p; IdentifierArrayType idArray(4); p[0] = -2; p[1] = -2; p[2] = -2; idArray[0] = meshSource->AddPoint(p); p[0] = 2; p[1] = 2; p[2] = -2; idArray[1] = meshSource->AddPoint(p); p[0] = 2; p[1] = -2; p[2] = 2; idArray[2] = meshSource->AddPoint(p); p[0] = -2; p[1] = 2; p[2] = 2; idArray[3] = meshSource->AddPoint(p); // Software Guide : EndCodeSnippet // Software Guide : BeginLatex // // Now we add the cells. This time we are just going to create the // boundary of a tetrahedron, so we must add each face separately. // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet meshSource->AddTriangle(idArray[0], idArray[1], idArray[2]); meshSource->AddTriangle(idArray[1], idArray[2], idArray[3]); meshSource->AddTriangle(idArray[2], idArray[3], idArray[0]); meshSource->AddTriangle(idArray[3], idArray[0], idArray[1]); // Software Guide : EndCodeSnippet // Software Guide : BeginLatex // // Actually, we could have called, e.g., \code{AddTriangle( 4, 5, 6 // )}, since IDs are assigned sequentially starting at zero, and // \code{idArray[0]} contains the ID for the fifth point added. // But you should only do this if you are confident that you know // what the IDs are. If you add the same point twice and don't // realize it, your count will differ from that of the mesh source. // // You may be wondering what happens if you call, say, // \code{AddEdge(0, 1)} followed by \code{AddEdge(1, 0)}. The // answer is that they do count as the same edge, and so only one // edge is added. The order of the vertices determines an // orientation, and the first orientation specified is the one that // is kept. // // Once you have built the mesh you want, you can access it by // calling \code{GetOutput()}. Here we send it to \code{cout}, // which prints some summary data for the mesh. // // Software Guide : EndLatex MeshType::Pointer mesh = meshSource->GetOutput(); std::cout << mesh << std::endl; // Software Guide : BeginLatex // // In contrast to the case with typical filters, \code{GetOutput()} does // not trigger an update process. The mesh is always maintained in a // valid state as cells are added, and can be accessed at any time. It // would, however, be a mistake to modify the mesh by some other means // until AutomaticTopologyMeshSource is done with it, since the mesh // source would then have an inaccurate record of which points and cells // are currently in the mesh. // // Software Guide : EndLatex return EXIT_SUCCESS; }