You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
13 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkDelaunay2D.h
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.
=========================================================================*/
/**
* @class vtkDelaunay2D
* @brief create 2D Delaunay triangulation of input points
*
* vtkDelaunay2D is a filter that constructs a 2D Delaunay triangulation from
* a list of input points. These points may be represented by any dataset of
* type vtkPointSet and subclasses. The output of the filter is a polygonal
* dataset. Usually the output is a triangle mesh, but if a non-zero alpha
* distance value is specified (called the "alpha" value), then only
* triangles, edges, and vertices laying within the alpha radius are
* output. In other words, non-zero alpha values may result in arbitrary
* combinations of triangles, lines, and vertices. (The notion of alpha value
* is derived from Edelsbrunner's work on "alpha shapes".) Also, it is
* possible to generate "constrained triangulations" using this filter.
* A constrained triangulation is one where edges and loops (i.e., polygons)
* can be defined and the triangulation will preserve them (read on for
* more information).
*
* The 2D Delaunay triangulation is defined as the triangulation that
* satisfies the Delaunay criterion for n-dimensional simplexes (in this case
* n=2 and the simplexes are triangles). This criterion states that a
* circumsphere of each simplex in a triangulation contains only the n+1
* defining points of the simplex. (See "The Visualization Toolkit" text
* for more information.) In two dimensions, this translates into an optimal
* triangulation. That is, the maximum interior angle of any triangle is less
* than or equal to that of any possible triangulation.
*
* Delaunay triangulations are used to build topological structures
* from unorganized (or unstructured) points. The input to this filter
* is a list of points specified in 3D, even though the triangulation
* is 2D. Thus the triangulation is constructed in the x-y plane, and
* the z coordinate is ignored (although carried through to the
* output). If you desire to triangulate in a different plane, you
* can use the vtkTransformFilter to transform the points into and
* out of the x-y plane or you can specify a transform to the Delaunay2D
* directly. In the latter case, the input points are transformed, the
* transformed points are triangulated, and the output will use the
* triangulated topology for the original (non-transformed) points. This
* avoids transforming the data back as would be required when using the
* vtkTransformFilter method. Specifying a transform directly also allows
* any transform to be used: rigid, non-rigid, non-invertible, etc.
*
* If an input transform is used, then alpha values are applied (for the
* most part) in the original data space. The exception is when
* BoundingTriangulation is on. In this case, alpha values are applied in
* the original data space unless a cell uses a bounding vertex.
*
* The Delaunay triangulation can be numerically sensitive in some cases. To
* prevent problems, try to avoid injecting points that will result in
* triangles with bad aspect ratios (1000:1 or greater). In practice this
* means inserting points that are "widely dispersed", and enables smooth
* transition of triangle sizes throughout the mesh. (You may even want to
* add extra points to create a better point distribution.) If numerical
* problems are present, you will see a warning message to this effect at
* the end of the triangulation process.
*
* To create constrained meshes, you must define an additional
* input. This input is an instance of vtkPolyData which contains
* lines, polylines, and/or polygons that define constrained edges and
* loops. Only the topology of (lines and polygons) from this second
* input are used. The topology is assumed to reference points in the
* input point set (the one to be triangulated). In other words, the
* lines and polygons use point ids from the first input point
* set. Lines and polylines found in the input will be mesh edges in
* the output. Polygons define a loop with inside and outside
* regions. The inside of the polygon is determined by using the
* right-hand-rule, i.e., looking down the z-axis a polygon should be
* ordered counter-clockwise. Holes in a polygon should be ordered
* clockwise. If you choose to create a constrained triangulation, the
* final mesh may not satisfy the Delaunay criterion. (Noted: the
* lines/polygon edges must not intersect when projected onto the 2D
* plane. It may not be possible to recover all edges due to not
* enough points in the triangulation, or poorly defined edges
* (coincident or excessively long). The form of the lines or
* polygons is a list of point ids that correspond to the input point
* ids used to generate the triangulation.)
*
* If an input transform is used, constraints are defined in the
* "transformed" space. So when the right hand rule is used for a
* polygon constraint, that operation is applied using the transformed
* points. Since the input transform can be any transformation (rigid
* or non-rigid), care must be taken in constructing constraints when
* an input transform is used.
*
* @warning
* Points arranged on a regular lattice (termed degenerate cases) can be
* triangulated in more than one way (at least according to the Delaunay
* criterion). The choice of triangulation (as implemented by
* this algorithm) depends on the order of the input points. The first three
* points will form a triangle; other degenerate points will not break
* this triangle.
*
* @warning
* Points that are coincident (or nearly so) may be discarded by the algorithm.
* This is because the Delaunay triangulation requires unique input points.
* You can control the definition of coincidence with the "Tolerance" instance
* variable.
*
* @warning
* The output of the Delaunay triangulation is supposedly a convex hull. In
* certain cases this implementation may not generate the convex hull. This
* behavior can be controlled by the Offset instance variable. Offset is a
* multiplier used to control the size of the initial triangulation. The
* larger the offset value, the more likely you will generate a convex hull;
* but the more likely you are to see numerical problems.
*
* @sa
* vtkDelaunay3D vtkTransformFilter vtkGaussianSplatter
*/
#ifndef vtkDelaunay2D_h
#define vtkDelaunay2D_h
#include "vtkFiltersCoreModule.h" // For export macro
#include "vtkPolyDataAlgorithm.h"
class vtkAbstractTransform;
class vtkCellArray;
class vtkIdList;
class vtkPointSet;
#define VTK_DELAUNAY_XY_PLANE 0
#define VTK_SET_TRANSFORM_PLANE 1
#define VTK_BEST_FITTING_PLANE 2
class VTKFILTERSCORE_EXPORT vtkDelaunay2D : public vtkPolyDataAlgorithm
{
public:
vtkTypeMacro(vtkDelaunay2D, vtkPolyDataAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Construct object with Alpha = 0.0; Tolerance = 0.001; Offset = 1.25;
* BoundingTriangulation turned off.
*/
static vtkDelaunay2D* New();
/**
* Specify the source object used to specify constrained edges and loops.
* (This is optional.) If set, and lines/polygons are defined, a constrained
* triangulation is created. The lines/polygons are assumed to reference
* points in the input point set (i.e. point ids are identical in the
* input and source).
* Note that this method does not connect the pipeline. See SetSourceConnection
* for connecting the pipeline.
*/
void SetSourceData(vtkPolyData*);
/**
* Specify the source object used to specify constrained edges and loops.
* (This is optional.) If set, and lines/polygons are defined, a constrained
* triangulation is created. The lines/polygons are assumed to reference
* points in the input point set (i.e. point ids are identical in the
* input and source).
* New style. This method is equivalent to SetInputConnection(1, algOutput).
*/
void SetSourceConnection(vtkAlgorithmOutput* algOutput);
/**
* Get a pointer to the source object.
*/
vtkPolyData* GetSource();
//@{
/**
* Specify alpha (or distance) value to control output of this filter.
* For a non-zero alpha value, only edges or triangles contained within
* a sphere centered at mesh vertices will be output. Otherwise, only
* triangles will be output.
*/
vtkSetClampMacro(Alpha, double, 0.0, VTK_DOUBLE_MAX);
vtkGetMacro(Alpha, double);
//@}
//@{
/**
* Specify a tolerance to control discarding of closely spaced points.
* This tolerance is specified as a fraction of the diagonal length of
* the bounding box of the points.
*/
vtkSetClampMacro(Tolerance, double, 0.0, 1.0);
vtkGetMacro(Tolerance, double);
//@}
//@{
/**
* Specify a multiplier to control the size of the initial, bounding
* Delaunay triangulation.
*/
vtkSetClampMacro(Offset, double, 0.75, VTK_DOUBLE_MAX);
vtkGetMacro(Offset, double);
//@}
//@{
/**
* Boolean controls whether bounding triangulation points (and associated
* triangles) are included in the output. (These are introduced as an
* initial triangulation to begin the triangulation process. This feature
* is nice for debugging output.)
*/
vtkSetMacro(BoundingTriangulation, vtkTypeBool);
vtkGetMacro(BoundingTriangulation, vtkTypeBool);
vtkBooleanMacro(BoundingTriangulation, vtkTypeBool);
//@}
//@{
/**
* Set / get the transform which is applied to points to generate a
* 2D problem. This maps a 3D dataset into a 2D dataset where
* triangulation can be done on the XY plane. The points are
* transformed and triangulated. The topology of triangulated
* points is used as the output topology. The output points are the
* original (untransformed) points. The transform can be any
* subclass of vtkAbstractTransform (thus it does not need to be a
* linear or invertible transform).
*/
virtual void SetTransform(vtkAbstractTransform*);
vtkGetObjectMacro(Transform, vtkAbstractTransform);
//@}
//@{
/**
* Define the method to project the input 3D points into a 2D plane for
* triangulation. When the VTK_DELAUNAY_XY_PLANE is set, the z-coordinate
* is simply ignored. When VTK_SET_TRANSFORM_PLANE is set, then a transform
* must be supplied and the points are transformed using it. Finally, if
* VTK_BEST_FITTING_PLANE is set, then the filter computes a best fitting
* plane and projects the points onto it.
*/
vtkSetClampMacro(ProjectionPlaneMode, int, VTK_DELAUNAY_XY_PLANE, VTK_BEST_FITTING_PLANE);
vtkGetMacro(ProjectionPlaneMode, int);
//@}
/**
* This method computes the best fit plane to a set of points represented
* by a vtkPointSet. The method constructs a transform and returns it on
* successful completion (null otherwise). The user is responsible for
* deleting the transform instance.
*/
static vtkAbstractTransform* ComputeBestFittingPlane(vtkPointSet* input);
protected:
vtkDelaunay2D();
~vtkDelaunay2D() override;
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
double Alpha;
double Tolerance;
vtkTypeBool BoundingTriangulation;
double Offset;
vtkAbstractTransform* Transform;
int ProjectionPlaneMode; // selects the plane in 3D where the Delaunay triangulation will be
// computed.
private:
vtkPolyData* Mesh; // the created mesh
double* Points; // the raw points in double precision
void SetPoint(vtkIdType id, double* x)
{
vtkIdType idx = 3 * id;
this->Points[idx] = x[0];
this->Points[idx + 1] = x[1];
this->Points[idx + 2] = x[2];
}
void GetPoint(vtkIdType id, double x[3])
{
double* ptr = this->Points + 3 * id;
x[0] = *ptr++;
x[1] = *ptr++;
x[2] = *ptr;
}
int NumberOfDuplicatePoints;
int NumberOfDegeneracies;
int* RecoverBoundary(vtkPolyData* source);
int RecoverEdge(vtkPolyData* source, vtkIdType p1, vtkIdType p2);
void FillPolygons(vtkCellArray* polys, int* triUse);
int InCircle(double x[3], double x1[3], double x2[3], double x3[3]);
vtkIdType FindTriangle(double x[3], vtkIdType ptIds[3], vtkIdType tri, double tol,
vtkIdType nei[3], vtkIdList* neighbors);
void CheckEdge(
vtkIdType ptId, double x[3], vtkIdType p1, vtkIdType p2, vtkIdType tri, bool recursive);
int FillInputPortInformation(int, vtkInformation*) override;
private:
vtkDelaunay2D(const vtkDelaunay2D&) = delete;
void operator=(const vtkDelaunay2D&) = delete;
};
#endif