You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
15 KiB
381 lines
15 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkDecimatePro.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 vtkDecimatePro - reduce the number of triangles in a mesh
|
|
// .SECTION Description
|
|
// vtkDecimatePro is a filter to reduce the number of triangles in a triangle
|
|
// mesh, forming a good approximation to the original geometry. The input to
|
|
// vtkDecimatePro is a vtkPolyData object, and only triangles are treated. If
|
|
// you desire to decimate polygonal meshes, first triangulate the polygons
|
|
// with vtkTriangleFilter object.
|
|
//
|
|
// The implementation of vtkDecimatePro is similar to the algorithm
|
|
// originally described in "Decimation of Triangle Meshes", Proc Siggraph
|
|
// `92, with three major differences. First, this algorithm does not
|
|
// necessarily preserve the topology of the mesh. Second, it is guaranteed to
|
|
// give the a mesh reduction factor specified by the user (as long as certain
|
|
// constraints are not set - see Caveats). Third, it is set up generate
|
|
// progressive meshes, that is a stream of operations that can be easily
|
|
// transmitted and incrementally updated (see Hugues Hoppe's Siggraph '96
|
|
// paper on progressive meshes).
|
|
//
|
|
// The algorithm proceeds as follows. Each vertex in the mesh is classified
|
|
// and inserted into a priority queue. The priority is based on the error to
|
|
// delete the vertex and retriangulate the hole. Vertices that cannot be
|
|
// deleted or triangulated (at this point in the algorithm) are
|
|
// skipped. Then, each vertex in the priority queue is processed (i.e.,
|
|
// deleted followed by hole triangulation using edge collapse). This
|
|
// continues until the priority queue is empty. Next, all remaining vertices
|
|
// are processed, and the mesh is split into separate pieces along sharp
|
|
// edges or at non-manifold attachment points and reinserted into the
|
|
// priority queue. Again, the priority queue is processed until empty. If
|
|
// the desired reduction is still not achieved, the remaining vertices are
|
|
// split as necessary (in a recursive fashion) so that it is possible to
|
|
// eliminate every triangle as necessary.
|
|
//
|
|
// To use this object, at a minimum you need to specify the ivar
|
|
// TargetReduction. The algorithm is guaranteed to generate a reduced mesh
|
|
// at this level as long as the following four conditions are met: 1)
|
|
// topology modification is allowed (i.e., the ivar PreserveTopology is off);
|
|
// 2) mesh splitting is enabled (i.e., the ivar Splitting is on); 3) the
|
|
// algorithm is allowed to modify the boundary of the mesh (i.e., the ivar
|
|
// BoundaryVertexDeletion is on); and 4) the maximum allowable error (i.e.,
|
|
// the ivar MaximumError) is set to VTK_DOUBLE_MAX. Other important
|
|
// parameters to adjust include the FeatureAngle and SplitAngle ivars, since
|
|
// these can impact the quality of the final mesh. Also, you can set the
|
|
// ivar AccumulateError to force incremental error update and distribution
|
|
// to surrounding vertices as each vertex is deleted. The accumulated error
|
|
// is a conservative global error bounds and decimation error, but requires
|
|
// additional memory and time to compute.
|
|
|
|
// .SECTION Caveats
|
|
// To guarantee a given level of reduction, the ivar PreserveTopology must
|
|
// be off; the ivar Splitting is on; the ivar BoundaryVertexDeletion is on;
|
|
// and the ivar MaximumError is set to VTK_DOUBLE_MAX.
|
|
//
|
|
// If PreserveTopology is off, and SplitEdges is off; the mesh topology may
|
|
// be modified by closing holes.
|
|
//
|
|
// Once mesh splitting begins, the feature angle is set to the split angle.
|
|
|
|
// .SECTION See Also
|
|
// vtkDecimate vtkQuadricClustering vtkQuadricDecimation
|
|
|
|
|
|
#ifndef __vtkDecimatePro_h
|
|
#define __vtkDecimatePro_h
|
|
|
|
#include "vtkPolyDataAlgorithm.h"
|
|
|
|
#include "vtkCell.h" // Needed for VTK_CELL_SIZE
|
|
|
|
class vtkDoubleArray;
|
|
class vtkPriorityQueue;
|
|
|
|
class VTK_GRAPHICS_EXPORT vtkDecimatePro : public vtkPolyDataAlgorithm
|
|
{
|
|
public:
|
|
vtkTypeRevisionMacro(vtkDecimatePro,vtkPolyDataAlgorithm);
|
|
void PrintSelf(ostream& os, vtkIndent indent);
|
|
|
|
// Description:
|
|
// Create object with specified reduction of 90% and feature angle of
|
|
// 15 degrees. Edge splitting is on, defer splitting is on, and the
|
|
// split angle is 75 degrees. Topology preservation is off, delete
|
|
// boundary vertices is on, and the maximum error is set to
|
|
// VTK_DOUBLE_MAX. The inflection point ratio is 10 and the vertex
|
|
// degree is 25. Error accumulation is turned off.
|
|
static vtkDecimatePro *New();
|
|
|
|
// Description:
|
|
// Specify the desired reduction in the total number of polygons (e.g., if
|
|
// TargetReduction is set to 0.9, this filter will try to reduce the data set
|
|
// to 10% of its original size). Because of various constraints, this level of
|
|
// reduction may not be realized. If you want to guarantee a particular
|
|
// reduction, you must turn off PreserveTopology, turn on SplitEdges and
|
|
// BoundaryVertexDeletion, and set the MaximumError to VTK_DOUBLE_MAX (these
|
|
// ivars are initialized this way when the object is instantiated).
|
|
vtkSetClampMacro(TargetReduction,double,0.0,1.0);
|
|
vtkGetMacro(TargetReduction,double);
|
|
|
|
// Description:
|
|
// Turn on/off whether to preserve the topology of the original mesh. If
|
|
// on, mesh splitting and hole elimination will not occur. This may limit
|
|
// the maximum reduction that may be achieved.
|
|
vtkSetMacro(PreserveTopology,int);
|
|
vtkGetMacro(PreserveTopology,int);
|
|
vtkBooleanMacro(PreserveTopology,int);
|
|
|
|
// Description:
|
|
// Specify the mesh feature angle. This angle is used to define what
|
|
// an edge is (i.e., if the surface normal between two adjacent triangles
|
|
// is >= FeatureAngle, an edge exists).
|
|
vtkSetClampMacro(FeatureAngle,double,0.0,180.0);
|
|
vtkGetMacro(FeatureAngle,double);
|
|
|
|
// Description:
|
|
// Turn on/off the splitting of the mesh at corners, along edges, at
|
|
// non-manifold points, or anywhere else a split is required. Turning
|
|
// splitting off will better preserve the original topology of the
|
|
// mesh, but you may not obtain the requested reduction.
|
|
vtkSetMacro(Splitting,int);
|
|
vtkGetMacro(Splitting,int);
|
|
vtkBooleanMacro(Splitting,int);
|
|
|
|
// Description:
|
|
// Specify the mesh split angle. This angle is used to control the splitting
|
|
// of the mesh. A split line exists when the surface normals between
|
|
// two edge connected triangles are >= SplitAngle.
|
|
vtkSetClampMacro(SplitAngle,double,0.0,180.0);
|
|
vtkGetMacro(SplitAngle,double);
|
|
|
|
// Description:
|
|
// In some cases you may wish to split the mesh prior to algorithm
|
|
// execution. This separates the mesh into semi-planar patches, which are
|
|
// disconnected from each other. This can give superior results in some
|
|
// cases. If the ivar PreSplitMesh ivar is enabled, the mesh is split with
|
|
// the specified SplitAngle. Otherwise mesh splitting is deferred as long
|
|
// as possible.
|
|
vtkSetMacro(PreSplitMesh,int);
|
|
vtkGetMacro(PreSplitMesh,int);
|
|
vtkBooleanMacro(PreSplitMesh,int);
|
|
|
|
// Description:
|
|
// Set the largest decimation error that is allowed during the decimation
|
|
// process. This may limit the maximum reduction that may be achieved. The
|
|
// maximum error is specified as a fraction of the maximum length of
|
|
// the input data bounding box.
|
|
vtkSetClampMacro(MaximumError,double,0.0,VTK_DOUBLE_MAX);
|
|
vtkGetMacro(MaximumError,double);
|
|
|
|
// Description:
|
|
// The computed error can either be computed directly from the mesh
|
|
// or the error may be accumulated as the mesh is modified. If the error
|
|
// is accumulated, then it represents a global error bounds, and the ivar
|
|
// MaximumError becomes a global bounds on mesh error. Accumulating the
|
|
// error requires extra memory proportional to the number of vertices in
|
|
// the mesh. If AccumulateError is off, then the error is not accumulated.
|
|
vtkSetMacro(AccumulateError,int);
|
|
vtkGetMacro(AccumulateError,int);
|
|
vtkBooleanMacro(AccumulateError,int);
|
|
|
|
// Description:
|
|
// The MaximumError is normally defined as a fraction of the dataset bounding
|
|
// diagonal. By setting ErrorIsAbsolute to 1, the error is instead defined
|
|
// as that specified by AbsoluteError. By default ErrorIsAbsolute=0.
|
|
vtkSetMacro(ErrorIsAbsolute,int);
|
|
vtkGetMacro(ErrorIsAbsolute,int);
|
|
|
|
// Description:
|
|
// Same as MaximumError, but to be used when ErrorIsAbsolute is 1
|
|
vtkSetClampMacro(AbsoluteError,double,0.0,VTK_DOUBLE_MAX);
|
|
vtkGetMacro(AbsoluteError,double);
|
|
|
|
// Description:
|
|
// Turn on/off the deletion of vertices on the boundary of a mesh. This
|
|
// may limit the maximum reduction that may be achieved.
|
|
vtkSetMacro(BoundaryVertexDeletion,int);
|
|
vtkGetMacro(BoundaryVertexDeletion,int);
|
|
vtkBooleanMacro(BoundaryVertexDeletion,int);
|
|
|
|
// Description:
|
|
// If the number of triangles connected to a vertex exceeds "Degree", then
|
|
// the vertex will be split. (NOTE: the complexity of the triangulation
|
|
// algorithm is proportional to Degree^2. Setting degree small can improve
|
|
// the performance of the algorithm.)
|
|
vtkSetClampMacro(Degree,int,25,VTK_CELL_SIZE);
|
|
vtkGetMacro(Degree,int);
|
|
|
|
// Description:
|
|
// Specify the inflection point ratio. An inflection point occurs
|
|
// when the ratio of reduction error between two iterations is greater
|
|
// than or equal to the InflectionPointRatio.
|
|
vtkSetClampMacro(InflectionPointRatio,double,1.001,VTK_DOUBLE_MAX);
|
|
vtkGetMacro(InflectionPointRatio,double);
|
|
|
|
|
|
// Description:
|
|
// Get the number of inflection points. Only returns a valid value after
|
|
// the filter has executed. The values in the list are mesh reduction
|
|
// values at each inflection point. Note: the first inflection point always
|
|
// occurs right before non-planar triangles are decimated (i.e., as the
|
|
// error becomes non-zero).
|
|
vtkIdType GetNumberOfInflectionPoints();
|
|
|
|
// Description:
|
|
// Get a list of inflection points. These are double values 0 < r <= 1.0
|
|
// corresponding to reduction level, and there are a total of
|
|
// NumberOfInflectionPoints() values. You must provide an array (of
|
|
// the correct size) into which the inflection points are written.
|
|
void GetInflectionPoints(double *inflectionPoints);
|
|
|
|
// Description:
|
|
// Get a list of inflection points. These are double values 0 < r <= 1.0
|
|
// corresponding to reduction level, and there are a total of
|
|
// NumberOfInflectionPoints() values. You must provide an array (of
|
|
// the correct size) into which the inflection points are written.
|
|
// This method returns a pointer to a list of inflection points.
|
|
double *GetInflectionPoints();
|
|
|
|
protected:
|
|
vtkDecimatePro();
|
|
~vtkDecimatePro();
|
|
|
|
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *);
|
|
|
|
double TargetReduction;
|
|
double FeatureAngle;
|
|
double MaximumError;
|
|
double AbsoluteError;
|
|
int ErrorIsAbsolute;
|
|
int AccumulateError;
|
|
double SplitAngle;
|
|
int Splitting;
|
|
int PreSplitMesh;
|
|
int BoundaryVertexDeletion;
|
|
int PreserveTopology;
|
|
int Degree;
|
|
double InflectionPointRatio;
|
|
vtkDoubleArray *InflectionPoints;
|
|
|
|
// to replace a static object
|
|
vtkIdList *Neighbors;
|
|
vtkPriorityQueue *EdgeLengths;
|
|
|
|
void SplitMesh();
|
|
int EvaluateVertex(vtkIdType ptId, unsigned short int numTris,
|
|
vtkIdType *tris, vtkIdType fedges[2]);
|
|
vtkIdType FindSplit(int type, vtkIdType fedges[2], vtkIdType& pt1,
|
|
vtkIdType& pt2, vtkIdList *CollapseTris);
|
|
int IsValidSplit(int index);
|
|
void SplitLoop(vtkIdType fedges[2], vtkIdType& n1, vtkIdType *l1,
|
|
vtkIdType& n2, vtkIdType *l2);
|
|
void SplitVertex(vtkIdType ptId,int type, unsigned short int numTris,
|
|
vtkIdType *tris, int insert);
|
|
int CollapseEdge(int type, vtkIdType ptId, vtkIdType collapseId,
|
|
vtkIdType pt1, vtkIdType pt2, vtkIdList *CollapseTris);
|
|
void DistributeError(double error);
|
|
|
|
//
|
|
// Special classes for manipulating data
|
|
//
|
|
//BTX - begin tcl exclude
|
|
//
|
|
// Special structures for building loops
|
|
class LocalVertex
|
|
{
|
|
public:
|
|
vtkIdType id;
|
|
double x[3];
|
|
double FAngle;
|
|
};
|
|
typedef LocalVertex *LocalVertexPtr;
|
|
|
|
class LocalTri
|
|
{
|
|
public:
|
|
vtkIdType id;
|
|
double area;
|
|
double n[3];
|
|
vtkIdType verts[3];
|
|
};
|
|
typedef LocalTri *LocalTriPtr;
|
|
|
|
class VertexArray;
|
|
friend class VertexArray;
|
|
class VertexArray { //;prevent man page generation
|
|
public:
|
|
VertexArray(const vtkIdType sz)
|
|
{this->MaxId = -1; this->Array = new LocalVertex[sz];};
|
|
~VertexArray()
|
|
{
|
|
if (this->Array)
|
|
{
|
|
delete [] this->Array;
|
|
}
|
|
};
|
|
vtkIdType GetNumberOfVertices() {return this->MaxId + 1;};
|
|
void InsertNextVertex(LocalVertex& v)
|
|
{this->MaxId++; this->Array[this->MaxId] = v;};
|
|
LocalVertex& GetVertex(vtkIdType i) {return this->Array[i];};
|
|
void Reset() {this->MaxId = -1;};
|
|
|
|
LocalVertex *Array; // pointer to data
|
|
vtkIdType MaxId; // maximum index inserted thus far
|
|
};
|
|
|
|
class TriArray;
|
|
friend class TriArray;
|
|
class TriArray { //;prevent man page generation
|
|
public:
|
|
TriArray(const vtkIdType sz)
|
|
{this->MaxId = -1; this->Array = new LocalTri[sz];};
|
|
~TriArray()
|
|
{
|
|
if (this->Array)
|
|
{
|
|
delete [] this->Array;
|
|
}
|
|
};
|
|
vtkIdType GetNumberOfTriangles() {return this->MaxId + 1;};
|
|
void InsertNextTriangle(LocalTri& t)
|
|
{this->MaxId++; this->Array[this->MaxId] = t;};
|
|
LocalTri& GetTriangle(vtkIdType i) {return this->Array[i];};
|
|
void Reset() {this->MaxId = -1;};
|
|
|
|
LocalTri *Array; // pointer to data
|
|
vtkIdType MaxId; // maximum index inserted thus far
|
|
};
|
|
//ETX - end tcl exclude
|
|
//
|
|
|
|
private:
|
|
void InitializeQueue(vtkIdType numPts);
|
|
void DeleteQueue();
|
|
void Insert(vtkIdType id, double error= -1.0);
|
|
int Pop(double &error);
|
|
double DeleteId(vtkIdType id);
|
|
void Reset();
|
|
|
|
vtkPriorityQueue *Queue;
|
|
vtkDoubleArray *VertexError;
|
|
|
|
VertexArray *V;
|
|
TriArray *T;
|
|
|
|
// Use to be static variables used by object
|
|
vtkPolyData *Mesh; //operate on this data structure
|
|
double Pt[3]; //least squares plane point
|
|
double Normal[3]; //least squares plane normal
|
|
double LoopArea; //the total area of all triangles in a loop
|
|
double CosAngle; //Cosine of dihedral angle
|
|
double Tolerance; //Intersection tolerance
|
|
double X[3]; //coordinates of current point
|
|
int NumCollapses; //Number of times edge collapses occur
|
|
int NumMerges; //Number of times vertex merges occur
|
|
int Split; //Controls whether and when vertex splitting occurs
|
|
int VertexDegree; //Maximum number of triangles that can use a vertex
|
|
vtkIdType NumberOfRemainingTris; //Number of triangles left in the mesh
|
|
double TheSplitAngle; //Split angle
|
|
int SplitState; //State of the splitting process
|
|
double Error; //Maximum allowable surface error
|
|
|
|
private:
|
|
vtkDecimatePro(const vtkDecimatePro&); // Not implemented.
|
|
void operator=(const vtkDecimatePro&); // Not implemented.
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|