/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkOrderedTriangulator.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ // .NAME vtkOrderedTriangulator - helper class to generate triangulations // .SECTION Description // This class is used to generate unique triangulations of points. The // uniqueness of the triangulation is controlled by the id of the inserted // points in combination with a Delaunay criterion. The class is designed to // be as fast as possible (since the algorithm can be slow) and uses block // memory allocations to support rapid triangulation generation. Also, the // assumption behind the class is that a maximum of hundreds of points are to // be triangulated. If you desire more robust triangulation methods use // vtkPolygon::Triangulate(), vtkDelaunay2D, or vtkDelaunay3D. // // .SECTION Background // This work is documented in the technical paper: W.J. Schroeder, B. Geveci, // M. Malaterre. Compatible Triangulations of Spatial Decompositions. In // Proceedings of Visualization 2004, IEEE Press October 2004. // // Delaunay triangulations are unique assuming a random distribution of input // points. The 3D Delaunay criterion is as follows: the circumsphere of each // tetrahedron contains no other points of the triangulation except for the // four points defining the tetrahedron. In application this property is // hard to satisfy because objects like cubes are defined by eight points all // sharing the same circumsphere (center and radius); hence the Delaunay // triangulation is not unique. These so-called degenerate situations are // typically resolved by arbitrary selecting a triangulation. This code does // something different: it resolves degenerate triangulations by modifying // the "InCircumsphere" method to use a slightly smaller radius. Hence, // degenerate points are always considered "out" of the circumsphere. This, // in combination with an ordering (based on id) of the input points, // guarantees a unique triangulation. // // There is another related characteristic of Delaunay triangulations. Given // a N-dimensional Delaunay triangulation, points lying on a (N-1) dimensional // plane also form a (N-1) Delaunay triangulation. This means for example, // that if a 3D cell is defined by a set of (2D) planar faces, then the // face triangulations are Delaunay. Combining this with the method to // generate unique triangulations described previously, the triangulations // on the face are guaranteed unique. This fact can be used to triangulate // 3D objects in such a way to guarantee compatible face triangulations. // This is a very useful fact for parallel processing, or performing // operations like clipping that require compatible triangulations across // 3D cell faces. (See vtkClipVolume for an example.) // // A special feature of this class is that it can generate triangulation // templates on the fly. If template triangulation is enabled, then the // ordered triangulator will first triangulate the cell using the slower // ordered Delaunay approach, and then store the result as a template. // Later, if the same cell type and cell configuration is encountered, // then the template is reused which greatly speeds the triangulation. // .SECTION Caveats // Duplicate vertices will be ignored, i.e., if two points have the same // coordinates the second one is discarded. The implications are that the // user of this class must prevent duplicate points. Because the precision // of this algorithm is double, it's also a good idea to merge points // that are within some epsilon of one another. // // The triangulation is performed using the parametric coordinates of the // inserted points. Therefore the bounds (see InitTriangulation()) should // represent the range of the parametric coordinates of the inserted points. // .SECTION See Also // vtkDelaunay2D vtkDelaunay3D vtkPolygon #ifndef __vtkOrderedTriangulator_h #define __vtkOrderedTriangulator_h #include "vtkObject.h" class vtkUnstructuredGrid; class vtkCellArray; class vtkHeap; class vtkIdList; class vtkPoints; class vtkTetra; class vtkDataArray; class vtkDoubleArray; struct vtkOTMesh; struct vtkOTTemplates; class vtkPointLocator; class vtkPointData; class vtkCellData; // Template ID's must be 32-bits. See .cxx file for more information. #if VTK_SIZEOF_SHORT == 4 typedef unsigned short TemplateIDType; #elif VTK_SIZEOF_INT == 4 typedef unsigned int TemplateIDType; #elif VTK_SIZEOF_LONG == 4 typedef unsigned long TemplateIDType; #endif class VTK_FILTERING_EXPORT vtkOrderedTriangulator : public vtkObject { public: vtkTypeRevisionMacro(vtkOrderedTriangulator,vtkObject); void PrintSelf(ostream& os, vtkIndent indent); // Description: // Construct object. static vtkOrderedTriangulator *New(); // Description: // Initialize the triangulation process. Provide a bounding box and // the maximum number of points to be inserted. Note that since the // triangulation is performed using parametric coordinates (see // InsertPoint()) the bounds should be represent the range of the // parametric coordinates inserted. // \post no_point_inserted: GetNumberOfPoints()==0 void InitTriangulation(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax, int numPts); void InitTriangulation(double bounds[6], int numPts); // Description: // For each point to be inserted, provide an id, a position x, parametric // coordinate p, and whether the point is inside (type=0), outside // (type=1), or on the boundary (type=2). You must call InitTriangulation() // prior to invoking this method. Make sure that the number of points // inserted does not exceed the numPts specified in // InitTriangulation(). Also note that the "id" can be any integer and can // be greater than numPts. It is used to create tetras (in AddTetras()) with // the appropriate connectivity ids. The method returns an internal id that // can be used prior to the Triangulate() method to update the type of the // point with UpdatePointType(). (Note: the algorithm triangulated with the // parametric coordinate p[3] and creates tetras with the global coordinate // x[3]. The parametric coordinates and global coordinates may be the same.) vtkIdType InsertPoint(vtkIdType id, double x[3], double p[3], int type); vtkIdType InsertPoint(vtkIdType id, vtkIdType sortid, double x[3], double p[3], int type); vtkIdType InsertPoint(vtkIdType id, vtkIdType sortid, vtkIdType sortid2, double x[3], double p[3], int type); // Description: // Perform the triangulation. (Complete all calls to InsertPoint() prior // to invoking this method.) A special version is available when templates // should be used. void Triangulate(); void TemplateTriangulate(int cellType, int numPts, int numEdges); // Description: // Update the point type. This is useful when the merging of nearly // coincident points is performed. The id is the internal id returned // from InsertPoint(). The method should be invoked prior to the // Triangulate method. The type is specified as inside (type=0), // outside (type=1), or on the boundary (type=2). // \pre valid_range: internalId>=0 && internalIdGetNumberOfPoints() void UpdatePointType(vtkIdType internalId, int type); // Description: // Return the parametric coordinates of point `internalId'. // It assumes that the point has already been inserted. // The method should be invoked prior to the Triangulate method. // \pre valid_range: internalId>=0 && internalIdGetNumberOfPoints() double *GetPointPosition(vtkIdType internalId); // Description: // Return the global coordinates of point `internalId'. // It assumes that the point has already been inserted. // The method should be invoked prior to the Triangulate method. // \pre valid_range: internalId>=0 && internalIdGetNumberOfPoints() double *GetPointLocation(vtkIdType internalId); // Description: // Return the Id of point `internalId'. This id is the one passed in // argument of InsertPoint. // It assumes that the point has already been inserted. // The method should be invoked prior to the Triangulate method. // \pre valid_range: internalId>=0 && internalIdGetNumberOfPoints() vtkIdType GetPointId(vtkIdType internalId); // Description: // Return the number of inserted points. vtkGetMacro(NumberOfPoints,int); // Description: // If this flag is set, then the ordered triangulator will create // and use templates for the triangulation. To use templates, the // TemplateTriangulate() method should be called when appropriate. // (Note: the TemplateTriangulate() method works for complete // (interior) cells without extra points due to intersection, etc.) vtkSetMacro(UseTemplates,int); vtkGetMacro(UseTemplates,int); vtkBooleanMacro(UseTemplates,int); // Description: // Boolean indicates whether the points have been pre-sorted. If // pre-sorted is enabled, the points are not sorted on point id. // By default, presorted is off. (The point id is defined in // InsertPoint().) vtkSetMacro(PreSorted,int); vtkGetMacro(PreSorted,int); vtkBooleanMacro(PreSorted,int); // Description: // Tells the triangulator that a second sort id is provided // for each point and should also be considered when sorting. vtkSetMacro(UseTwoSortIds,int); vtkGetMacro(UseTwoSortIds,int); vtkBooleanMacro(UseTwoSortIds,int); // Description: // Initialize and add the tetras and points from the triangulation to the // unstructured grid provided. New points are created and the mesh is // allocated. (This method differs from AddTetras() in that it inserts // points and cells; AddTetras only adds the tetra cells.) The tetrahdera // added are of the type specified (0=inside,1=outside,2=all). Inside // tetrahedron are those whose points are classified "inside" or on the // "boundary." Outside tetrahedron have at least one point classified // "outside." The method returns the number of tetrahedrahedron of the // type requested. vtkIdType GetTetras(int classification, vtkUnstructuredGrid *ugrid); // Description: // Add the tetras to the unstructured grid provided. The unstructured // grid is assumed to have been initialized (with Allocate()) and // points set (with SetPoints()). The tetrahdera added are of the type // specified (0=inside,1=outside,2=all). Inside tetrahedron are // those whose points are classified "inside" or on the "boundary." // Outside tetrahedron have at least one point classified "outside." // The method returns the number of tetrahedrahedron of the type // requested. vtkIdType AddTetras(int classification, vtkUnstructuredGrid *ugrid); // Description: // Add the tetrahedra classified (0=inside,1=outside) to the connectivity // list provided. Inside tetrahedron are those whose points are all // classified "inside." Outside tetrahedron have at least one point // classified "outside." The method returns the number of tetrahedron // of the type requested. vtkIdType AddTetras(int classification, vtkCellArray *connectivity); // Description: // Assuming that all the inserted points come from a cell `cellId' to // triangulate, get the tetrahedra in outConnectivity, the points in locator // and copy point data and cell data. Return the number of added tetras. // \pre locator_exists: locator!=0 // \pre outConnectivity: outConnectivity!=0 // \pre inPD_exists: inPD!=0 // \pre outPD_exists: outPD!=0 // \pre inCD_exists: inCD!=0 // \pre outCD_exists: outCD!=0 vtkIdType AddTetras(int classification, vtkPointLocator *locator, vtkCellArray *outConnectivity, vtkPointData *inPD, vtkPointData *outPD, vtkCellData *inCD, vtkIdType cellId, vtkCellData *outCD); // Description: // Add the tetrahedra classified (0=inside,1=outside) to the list // of ids and coordinates provided. These assume that the first four points // form a tetrahedron, the next four the next, and so on. vtkIdType AddTetras(int classification, vtkIdList *ptIds, vtkPoints *pts); // Description: // Add the triangle faces classified (2=boundary) to the connectivity // list provided. The method returns the number of triangles. vtkIdType AddTriangles(vtkCellArray *connectivity); // Description: // Add the triangle faces classified (2=boundary) and attached to the // specified point id to the connectivity list provided. (The id is the // same as that specified in InsertPoint().) vtkIdType AddTriangles(vtkIdType id, vtkCellArray *connectivity); // Description: // Methods to get one tetra at a time. Start with InitTetraTraversal() // and then invoke GetNextTetra() until the method returns 0. void InitTetraTraversal(); // Description: // Methods to get one tetra at a time. Start with InitTetraTraversal() // and then invoke GetNextTetra() until the method returns 0. // cellScalars are point-centered scalars on the original cell. // tetScalars are point-centered scalars on the tetra: the values will be // copied from cellScalars. // \pre tet_exists: tet!=0 // \pre cellScalars_exists: cellScalars!=0 // \pre tetScalars_exists: tetScalars!=0 // \pre tetScalars_valid_size: tetScalars->GetNumberOfTuples()==4 int GetNextTetra(int classification, vtkTetra *tet, vtkDataArray *cellScalars, vtkDoubleArray *tetScalars); protected: vtkOrderedTriangulator(); ~vtkOrderedTriangulator(); private: void Initialize(); vtkOTMesh *Mesh; int NumberOfPoints; //number of points inserted int MaximumNumberOfPoints; //maximum possible number of points to be inserted double Bounds[6]; int PreSorted; int UseTwoSortIds; vtkHeap *Heap; double Quanta; int UseTemplates; int CellType; int NumberOfCellPoints; int NumberOfCellEdges; vtkHeap *TemplateHeap; vtkOTTemplates *Templates; int TemplateTriangulation(); void AddTemplate(); TemplateIDType ComputeTemplateIndex(); private: vtkOrderedTriangulator(const vtkOrderedTriangulator&); // Not implemented. void operator=(const vtkOrderedTriangulator&); // Not implemented. }; #endif