/*=========================================================================
*
* Copyright Insight Software Consortium
*
* 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.
*
*=========================================================================*/
#ifndef itkAutomaticTopologyMeshSource_h
#define itkAutomaticTopologyMeshSource_h
#include "itkArray.h"
#include "itkDefaultStaticMeshTraits.h"
#include "itksys/hash_map.hxx"
#include "itkHexahedronCell.h"
#include "itkIntTypes.h"
#include "itkMesh.h"
#include "itkMeshSource.h"
#include "itkStructHashFunction.h"
#include "itkTetrahedronCell.h"
#include "itkVertexCell.h"
namespace itk
{
/** \class AutomaticTopologyMeshSource
* \brief Convenience class for generating meshes.
*
* This generates an N-dimensional mesh consisting of some combination
* of vertices, line segments, triangles, quadrilaterals, tetrahedra,
* and hexahedra. Identifiers for the cells are automatically added,
* and topological connectivity is automatically computed. When a
* cell is added, all of its boundary features are determined and
* added as well.
*
* The main methods are of the form AddThing, where
* Thing can be Point, Vertex, Triangle, Quadrilateral,
* Tetrahedron, or Hexahedron. Each of these methods has several
* overloaded forms, permitting multiple ways to specify the object
* being added. When called, each of these methods first checks to
* see if the object has already been added. If it has not, then a
* new identifier is generated (the smallest one so far unused), the
* object is added with that identifier, and the ID is returned. If
* the object has already been added, then the ID it already has is
* returned and nothing else is done.
*
* When a cell is added, all of its boundary elements are also added,
* and boundary assignments are set. A cell can be specified using
* IDs of points already added, or using Point objects that may or may
* not already be in the mesh. If a cell is specified using Point
* objects, then the points are added to the mesh if necessary.
*
* The different ways of specifying a cell are
*
* \li An IdentifierArrayType (= itk::Array) of point
* identifiers. These point identifiers are the ones returned by
* calls to AddPoint().
* \li A parameter list of point identifiers (for instance,
* this->AddLine(0, 1), if 0 and 1 are point identifiers).
* \li A parameter list of itk::Point objects (the function then
* generates the identifiers).
* \li A parameter list of C-style arrays, with each such array giving
* the coordinates of one point. This form is useful for copying
* in geometry from foreign data structures.
*
* For meshes generated using this filter, only one cell can be added
* for any given set of vertices. If a, b, c, and d are identifiers
* for four points in R^3, then (a, b, c, d) and (a, c, d, b)
* determine two different quadrilaterals (at least one of which is
* either degenerate or nonplanar). If you call
* \code
* AddQuadrilateral(a, b, c, d);
* AddQuadrilateral(a, c, d, b);
* \endcode
* then only the first quadrilateral will actually be added.
*
* To add the topological information to an already constructed mesh
* (for efficiency of traversal), use this class to generate a copy of
* the original mesh.
*
* \b Example: The following code generates a mesh consisting of two
* triangles sharing an edge.
* \code
* typedef itk::AutomaticTopologyMeshSource< MeshType > MeshSourceType;
* MeshSourceType::Pointer meshSource = MeshSourceType::New();
* meshSource->AddTriangle(
* meshSource->AddPoint(0, 0, 0),
* meshSource->AddPoint(1, 0, 0),
* meshSource->AddPoint(0, 1, 0) );
* meshSource->AddTriangle(
* meshSource->AddPoint(0, 0, 0),
* meshSource->AddPoint(1, 0, 0),
* meshSource->AddPoint(0, 0, 1) );
* \endcode
*
* This class inherits from itk::MeshSource so it fits conveniently into a
* pipeline, but GetOutput() is always valid after every
* Add[Something]() call, and Update() is a no-op. It is not
* thread safe.
* \ingroup ITKMesh
*/
template< typename TOutputMesh >
class ITK_TEMPLATE_EXPORT AutomaticTopologyMeshSource:public MeshSource< TOutputMesh >
{
public:
/** Standard "Self" typedef. */
typedef AutomaticTopologyMeshSource Self;
typedef MeshSource< TOutputMesh > Superclass;
typedef SmartPointer< Self > Pointer;
typedef SmartPointer< const Self > ConstPointer;
/** Hold on to the type information specified by the template parameters. */
typedef TOutputMesh MeshType;
typedef typename MeshType::PointHashType PointHashType;
typedef typename MeshType::PointType PointType;
typedef typename MeshType::CellType CellType;
typedef typename MeshType::Pointer MeshPointer;
typedef typename PointType::CoordRepType CoordinateType;
typedef typename CellType::CellAutoPointer CellAutoPointer;
/** Different kinds of cells. */
typedef::itk::VertexCell< CellType > VertexCell;
typedef::itk::LineCell< CellType > LineCell;
typedef::itk::TriangleCell< CellType > TriangleCell;
typedef::itk::QuadrilateralCell< CellType > QuadrilateralCell;
typedef::itk::TetrahedronCell< CellType > TetrahedronCell;
typedef::itk::HexahedronCell< CellType > HexahedronCell;
/** This class requires that the mesh being built use ::itk::IdentifierType
* as the identifier type for all its elements. */
typedef ::itk::IdentifierType IdentifierType;
/** Array of IdentifierType objects used to specify cells. */
typedef Array< IdentifierType > IdentifierArrayType;
/** hash_map typedefs. */
typedef itksys::hash_map<
PointType,
IdentifierType,
StructHashFunction< PointHashType > > PointHashMap;
/** The dimension of the output mesh. */
itkStaticConstMacro(PointDimension, unsigned int,
MeshType::PointDimension);
itkStaticConstMacro(MaxTopologicalDimension, unsigned int,
MeshType::MaxTopologicalDimension);
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(AutomaticTopologyMeshSource, MeshSource);
/** Add the point p0 if it's not already there, and return its ID. */
IdentifierType AddPoint(const PointType & p0);
IdentifierType AddPoint(const CoordinateType *p0);
/** Add the point with coordinates (x0, ..., xN) where N =
* PointDimension - 1. If N < 5, then any parameters after xN are
* ignored. If PointDimension > 6, then a point is generated with
* the first six coordinates equal to x0, ..., x5, and the rest set
* to 0. */
IdentifierType AddPoint(CoordinateType x0 = 0, CoordinateType x1 = 0,
CoordinateType x2 = 0, CoordinateType x3 = 0,
CoordinateType x4 = 0, CoordinateType x5 = 0);
/** Add a vertex located at the given point, and return its ID. */
IdentifierType AddVertex(const IdentifierArrayType & pointIds);
IdentifierType AddVertex(IdentifierType pointId0);
IdentifierType AddVertex(const PointType & p0);
IdentifierType AddVertex(const CoordinateType *p0);
/** Add the line specified by the two points, and return its ID.
* The endpoints and their associated vertices are associated to the
* line in the order that they are specified the first time the
* function is called. */
IdentifierType AddLine(const IdentifierArrayType & pointIds);
IdentifierType AddLine(
IdentifierType pointId0, IdentifierType pointId1);
IdentifierType AddLine(const PointType & p0, const PointType & p1);
IdentifierType AddLine(const CoordinateType *p0,
const CoordinateType *p1);
/** Add the triangle specified by the three points, and return its
* ID. If the points are p0, p1, and p2, then the following
* additional cells (represented here as ordered tuples) are created
* (if they don't already exist) and associated as boundaries, in
* the order given:
*
* Vertices: (p0), (p1), (p2).
*
* Lines: (p0, p1), (p1, p2), (p2, p0).
* */
IdentifierType AddTriangle(const IdentifierArrayType & pointIds);
IdentifierType AddTriangle(
IdentifierType pointId0, IdentifierType pointId1,
IdentifierType pointId2);
IdentifierType AddTriangle(const PointType & p0, const PointType & p1,
const PointType & p2);
IdentifierType AddTriangle(const CoordinateType *p0,
const CoordinateType *p1,
const CoordinateType *p2);
/** Add the quadrilateral specified by the four points, and return its
* ID. If the points are p0, p1, p2, and p3, then the following
* additional cells (represented here as ordered tuples) are created
* (if they don't already exist) and associated as boundaries, in
* the order given:
*
* Vertices: (p0), (p1), (p2), (p3).
*
* Lines: (p0, p1), (p2, p3), (p0, p2), (p1, p3).
*
* In particular, if the points are arranged geometrically as follows
\verbatim
p0 p1
p2 p3
\endverbatim
*
* then you would call, for instance,
* meshSource->AddQuadrilateral(p0, p1, p2, p3).
* */
IdentifierType AddQuadrilateral(const IdentifierArrayType & pointIds);
IdentifierType AddQuadrilateral(
IdentifierType pointId0, IdentifierType pointId1,
IdentifierType pointId2, IdentifierType pointId3);
IdentifierType AddQuadrilateral(const PointType & p0, const PointType & p1,
const PointType & p2, const PointType & p3);
IdentifierType AddQuadrilateral(const CoordinateType *p0,
const CoordinateType *p1,
const CoordinateType *p2,
const CoordinateType *p3);
/** Add the tetrahedron specified by the three points, and return its
* ID. If the points are p0, p1, and p2, then the following
* additional cells (represented here as ordered tuples) are created
* (if they don't already exist) and associated as boundaries, in
* the order given:
*
* Vertices: (p0), (p1), (p2), (p3).
*
* Lines: (p0, p1), (p0, p2), (p0, p3), (p1, p2), (p1, p3), (p2, p3).
*
* Triangles: (p0, p1, p2), (p0, p1, p3), (p0, p2, p3), (p1, p2, * p3).
* */
IdentifierType AddTetrahedron(const IdentifierArrayType & pointIds);
IdentifierType AddTetrahedron(
IdentifierType pointId0, IdentifierType pointId1,
IdentifierType pointId2, IdentifierType pointId3);
IdentifierType AddTetrahedron(const PointType & p0, const PointType & p1,
const PointType & p2, const PointType & p3);
IdentifierType AddTetrahedron(const CoordinateType *p0,
const CoordinateType *p1,
const CoordinateType *p2,
const CoordinateType *p3);
/** Add the hexahedron specified by the four points, and return its
* ID. If the points are p0, p1, p2, and p3, then the following
* additional cells (represented here as ordered tuples) are created
* (if they don't already exist) and associated as boundaries, in
* the order given:
*
* Vertices: (p0), (p1), (p2), (p3), (p4), (p5), (p6), (p7).
*
* Lines: (p0, p1), (p2, p3), (p4, p5), (p6, p7), (p0, p2), (p1,
* p3), (p4, p6), (p5, p7), (p0, p4), (p1, p5), (p2, p6), (p3, p7).
*
* Quadrilaterals: (0, 1, 2, 3), (4, 5, 6, 7), (0, 1, 4, 5), (2, 3,
* 6, 7), (0, 2, 4, 6), (1, 3, 5, 7),
*
* In particular, if the points are connected topologically as follows
\verbatim
p4------------p5
| \ / |
| p0------p1 |
| | | |
| | | |
| p2------p3 |
| / \ |
p6------------p7
\endverbatim
* then you would call, for instance,
* meshSource->AddQuadrilateral(p0, p1, p2, p3, p4, p5, p6,
* p7). */
IdentifierType AddHexahedron(const IdentifierArrayType & pointIds);
IdentifierType AddHexahedron(
IdentifierType pointId0, IdentifierType pointId1,
IdentifierType pointId2, IdentifierType pointId3,
IdentifierType pointId4, IdentifierType pointId5,
IdentifierType pointId6, IdentifierType pointId7);
IdentifierType AddHexahedron(
const PointType & p0, const PointType & p1, const PointType & p2,
const PointType & p3, const PointType & p4, const PointType & p5,
const PointType & p6, const PointType & p7
);
IdentifierType AddHexahedron(const CoordinateType *p0,
const CoordinateType *p1,
const CoordinateType *p2,
const CoordinateType *p3,
const CoordinateType *p4,
const CoordinateType *p5,
const CoordinateType *p6,
const CoordinateType *p7);
class IdentifierArrayHashFunction
{
public:
IdentifierType operator()(Array< IdentifierType > identifierArray) const
{
typedef IdentifierType IdType;
IdType size = identifierArray.Size();
std::sort( identifierArray.begin(), identifierArray.end() );
IdType hash = 0;
IdType *id = &identifierArray[0];
while ( size-- )
{
hash += *id++;
hash = ( hash << 7 ) | ( hash >> 25 ); // Rotate left by 7.
}
return hash;
}
};
class IdentifierArrayEqualsFunction
{
public:
bool operator()(
Array< IdentifierType > identifierArray1,
Array< IdentifierType > identifierArray2
) const
{
typedef IdentifierType IdType;
IdType size1 = identifierArray1.Size();
IdType size2 = identifierArray2.Size();
if ( size1 != size2 )
{
return false;
}
std::sort( identifierArray1.begin(), identifierArray1.end() );
std::sort( identifierArray2.begin(), identifierArray2.end() );
return ( identifierArray1 == identifierArray2 );
}
};
protected:
AutomaticTopologyMeshSource();
~AutomaticTopologyMeshSource() ITK_OVERRIDE;
void GenerateData() ITK_OVERRIDE {} // GenerateData is a no-op, since the entries ITK_OVERRIDE
// are controlled manually
private:
ITK_DISALLOW_COPY_AND_ASSIGN(AutomaticTopologyMeshSource);
typedef itksys::hash_map<
Array< IdentifierType >,
IdentifierType,
IdentifierArrayHashFunction,
IdentifierArrayEqualsFunction > CellHashMap;
PointHashMap m_PointsHashTable;
CellHashMap m_CellsHashTable;
MeshPointer m_OutputMesh; // Retained for convenience.
};
} // end namespace itk
#ifndef ITK_MANUAL_INSTANTIATION
#include "itkAutomaticTopologyMeshSource.hxx"
#endif
#endif // itkAutomaticTopologyMeshSource_h