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.
258 lines
9.8 KiB
C
258 lines
9.8 KiB
C
3 weeks ago
|
/*=========================================================================
|
||
|
|
||
|
Program: Visualization Toolkit
|
||
|
Module: vtkGreedyTerrainDecimation.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 vtkGreedyTerrainDecimation
|
||
|
* @brief reduce height field (represented as image) to reduced TIN
|
||
|
*
|
||
|
* vtkGreedyTerrainDecimation approximates a height field with a triangle
|
||
|
* mesh (triangulated irregular network - TIN) using a greedy insertion
|
||
|
* algorithm similar to that described by Garland and Heckbert in their paper
|
||
|
* "Fast Polygonal Approximations of Terrain and Height Fields" (Technical
|
||
|
* Report CMU-CS-95-181). The input to the filter is a height field
|
||
|
* (represented by a image whose scalar values are height) and the output of
|
||
|
* the filter is polygonal data consisting of triangles. The number of
|
||
|
* triangles in the output is reduced in number as compared to a naive
|
||
|
* tessellation of the input height field. This filter copies point data
|
||
|
* from the input to the output for those points present in the output.
|
||
|
*
|
||
|
* An brief description of the algorithm is as follows. The algorithm uses a
|
||
|
* top-down decimation approach that initially represents the height field
|
||
|
* with two triangles (whose vertices are at the four corners of the
|
||
|
* image). These two triangles form a Delaunay triangulation. In an iterative
|
||
|
* fashion, the point in the image with the greatest error (as compared to
|
||
|
* the original height field) is injected into the triangulation. (Note that
|
||
|
* the single point with the greatest error per triangle is identified and
|
||
|
* placed into a priority queue. As the triangulation is modified, the errors
|
||
|
* from the deleted triangles are removed from the queue, error values from
|
||
|
* the new triangles are added.) The point whose error is at the top of the
|
||
|
* queue is added to the triangulaion modifying it using the standard
|
||
|
* incremental Delaunay point insertion (see vtkDelaunay2D) algorithm. Points
|
||
|
* are repeatedly inserted until the appropriate (user-specified) error
|
||
|
* criterion is met.
|
||
|
*
|
||
|
* To use this filter, set the input and specify the error measure to be
|
||
|
* used. The error measure options are 1) the absolute number of triangles
|
||
|
* to be produced; 2) a fractional reduction of the mesh (numTris/maxTris)
|
||
|
* where maxTris is the largest possible number of triangles
|
||
|
* 2*(dims[0]-1)*(dims[1]-1); 3) an absolute measure on error (maximum
|
||
|
* difference in height field to reduced TIN); and 4) relative error (the
|
||
|
* absolute error is normalized by the diagonal of the bounding box of the
|
||
|
* height field).
|
||
|
*
|
||
|
* @warning
|
||
|
* This algorithm requires the entire input dataset to be in memory, hence it
|
||
|
* may not work for extremely large images. Invoking BoundaryVertexDeletionOff
|
||
|
* will allow you to stitch together images with matching boundaries.
|
||
|
*
|
||
|
* @warning
|
||
|
* The input height image is assumed to be positioned in the x-y plane so the
|
||
|
* scalar value is the z-coordinate, height value.
|
||
|
*
|
||
|
* @sa
|
||
|
* vtkDecimatePro vtkQuadricDecimation vtkQuadricClustering
|
||
|
*/
|
||
|
|
||
|
#ifndef vtkGreedyTerrainDecimation_h
|
||
|
#define vtkGreedyTerrainDecimation_h
|
||
|
|
||
|
#include "vtkFiltersHybridModule.h" // For export macro
|
||
|
#include "vtkPolyDataAlgorithm.h"
|
||
|
|
||
|
class vtkPriorityQueue;
|
||
|
class vtkDataArray;
|
||
|
class vtkPointData;
|
||
|
class vtkIdList;
|
||
|
class vtkDoubleArray;
|
||
|
class vtkFloatArray;
|
||
|
|
||
|
// PIMPL Encapsulation for STL containers
|
||
|
class vtkGreedyTerrainDecimationTerrainInfoType;
|
||
|
class vtkGreedyTerrainDecimationPointInfoType;
|
||
|
|
||
|
#define VTK_ERROR_NUMBER_OF_TRIANGLES 0
|
||
|
#define VTK_ERROR_SPECIFIED_REDUCTION 1
|
||
|
#define VTK_ERROR_ABSOLUTE 2
|
||
|
#define VTK_ERROR_RELATIVE 3
|
||
|
|
||
|
class VTKFILTERSHYBRID_EXPORT vtkGreedyTerrainDecimation : public vtkPolyDataAlgorithm
|
||
|
{
|
||
|
public:
|
||
|
vtkTypeMacro(vtkGreedyTerrainDecimation, vtkPolyDataAlgorithm);
|
||
|
void PrintSelf(ostream& os, vtkIndent indent) override;
|
||
|
|
||
|
/**
|
||
|
* Instantiate the class.
|
||
|
*/
|
||
|
static vtkGreedyTerrainDecimation* New();
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Specify how to terminate the algorithm: either as an absolute number of
|
||
|
* triangles, a relative number of triangles (normalized by the full
|
||
|
* resolution mesh), an absolute error (in the height field), or relative
|
||
|
* error (normalized by the length of the diagonal of the image).
|
||
|
*/
|
||
|
vtkSetClampMacro(ErrorMeasure, int, VTK_ERROR_NUMBER_OF_TRIANGLES, VTK_ERROR_RELATIVE);
|
||
|
vtkGetMacro(ErrorMeasure, int);
|
||
|
void SetErrorMeasureToNumberOfTriangles()
|
||
|
{
|
||
|
this->SetErrorMeasure(VTK_ERROR_NUMBER_OF_TRIANGLES);
|
||
|
}
|
||
|
void SetErrorMeasureToSpecifiedReduction()
|
||
|
{
|
||
|
this->SetErrorMeasure(VTK_ERROR_SPECIFIED_REDUCTION);
|
||
|
}
|
||
|
void SetErrorMeasureToAbsoluteError() { this->SetErrorMeasure(VTK_ERROR_ABSOLUTE); }
|
||
|
void SetErrorMeasureToRelativeError() { this->SetErrorMeasure(VTK_ERROR_RELATIVE); }
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Specify the number of triangles to produce on output. (It is a
|
||
|
* good idea to make sure this is less than a tessellated mesh
|
||
|
* at full resolution.) You need to set this value only when
|
||
|
* the error measure is set to NumberOfTriangles.
|
||
|
*/
|
||
|
vtkSetClampMacro(NumberOfTriangles, vtkIdType, 2, VTK_ID_MAX);
|
||
|
vtkGetMacro(NumberOfTriangles, vtkIdType);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Specify the reduction of the mesh (represented as a fraction). Note
|
||
|
* that a value of 0.10 means a 10% reduction. You need to set this value
|
||
|
* only when the error measure is set to SpecifiedReduction.
|
||
|
*/
|
||
|
vtkSetClampMacro(Reduction, double, 0.0, 1.0);
|
||
|
vtkGetMacro(Reduction, double);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Specify the absolute error of the mesh; that is, the error in height
|
||
|
* between the decimated mesh and the original height field. You need to
|
||
|
* set this value only when the error measure is set to AbsoluteError.
|
||
|
*/
|
||
|
vtkSetClampMacro(AbsoluteError, double, 0.0, VTK_DOUBLE_MAX);
|
||
|
vtkGetMacro(AbsoluteError, double);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Specify the relative error of the mesh; that is, the error in height
|
||
|
* between the decimated mesh and the original height field normalized by
|
||
|
* the diagonal of the image. You need to set this value only when the
|
||
|
* error measure is set to RelativeError.
|
||
|
*/
|
||
|
vtkSetClampMacro(RelativeError, double, 0.0, VTK_DOUBLE_MAX);
|
||
|
vtkGetMacro(RelativeError, double);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* 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, vtkTypeBool);
|
||
|
vtkGetMacro(BoundaryVertexDeletion, vtkTypeBool);
|
||
|
vtkBooleanMacro(BoundaryVertexDeletion, vtkTypeBool);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Compute normals based on the input image. Off by default.
|
||
|
*/
|
||
|
vtkSetMacro(ComputeNormals, vtkTypeBool);
|
||
|
vtkGetMacro(ComputeNormals, vtkTypeBool);
|
||
|
vtkBooleanMacro(ComputeNormals, vtkTypeBool);
|
||
|
//@}
|
||
|
|
||
|
protected:
|
||
|
vtkGreedyTerrainDecimation();
|
||
|
~vtkGreedyTerrainDecimation() override;
|
||
|
|
||
|
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
|
||
|
int FillInputPortInformation(int port, vtkInformation* info) override;
|
||
|
|
||
|
vtkTypeBool ComputeNormals;
|
||
|
vtkFloatArray* Normals;
|
||
|
void ComputePointNormal(int i, int j, float n[3]);
|
||
|
|
||
|
// ivars that the API addresses
|
||
|
int ErrorMeasure;
|
||
|
vtkIdType NumberOfTriangles;
|
||
|
double Reduction;
|
||
|
double AbsoluteError;
|
||
|
double RelativeError;
|
||
|
vtkTypeBool BoundaryVertexDeletion; // Can we delete boundary vertices?
|
||
|
|
||
|
// Used for convenience
|
||
|
vtkPolyData* Mesh;
|
||
|
vtkPointData* InputPD;
|
||
|
vtkPointData* OutputPD;
|
||
|
vtkDoubleArray* Points;
|
||
|
vtkDataArray* Heights;
|
||
|
vtkIdType CurrentPointId;
|
||
|
double Tolerance;
|
||
|
vtkIdList* Neighbors;
|
||
|
int Dimensions[3];
|
||
|
double Origin[3];
|
||
|
double Spacing[3];
|
||
|
vtkIdType MaximumNumberOfTriangles;
|
||
|
double Length;
|
||
|
|
||
|
// Bookkeeping arrays
|
||
|
vtkPriorityQueue* TerrainError; // errors for each pt in height field
|
||
|
vtkGreedyTerrainDecimationTerrainInfoType* TerrainInfo; // owning triangle for each pt
|
||
|
vtkGreedyTerrainDecimationPointInfoType* PointInfo; // map mesh pt id to input pt id
|
||
|
|
||
|
// Make a guess at initial allocation
|
||
|
void EstimateOutputSize(const vtkIdType numInputPts, vtkIdType& numPts, vtkIdType& numTris);
|
||
|
|
||
|
// Returns non-zero if the error measure is satisfied.
|
||
|
virtual int SatisfiesErrorMeasure(double error);
|
||
|
|
||
|
// Insert all the boundary vertices into the TIN
|
||
|
void InsertBoundaryVertices();
|
||
|
|
||
|
// Insert a point into the triangulation; get a point from the triangulation
|
||
|
vtkIdType AddPointToTriangulation(vtkIdType inputPtId);
|
||
|
vtkIdType InsertNextPoint(vtkIdType inputPtId, double x[3]);
|
||
|
double* GetPoint(vtkIdType id);
|
||
|
void GetPoint(vtkIdType id, double x[3]);
|
||
|
|
||
|
// Helper functions
|
||
|
void GetTerrainPoint(int i, int j, double x[3]);
|
||
|
void ComputeImageCoordinates(vtkIdType inputPtId, int ij[2]);
|
||
|
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, int& status);
|
||
|
void CheckEdge(vtkIdType ptId, double x[3], vtkIdType p1, vtkIdType p2, vtkIdType tri, int depth);
|
||
|
|
||
|
void UpdateTriangles(vtkIdType meshPtId); // update all points connected to this point
|
||
|
void UpdateTriangle(vtkIdType triId, vtkIdType p1, vtkIdType p2, vtkIdType p3);
|
||
|
void UpdateTriangle(vtkIdType triId, int ij1[2], int ij2[2], int ij3[2], double h[4]);
|
||
|
|
||
|
int CharacterizeTriangle(int ij1[2], int ij2[2], int ij[3], int*& min, int*& max, int*& midL,
|
||
|
int*& midR, int*& mid, int mid2[2], double h[3], double& hMin, double& hMax, double& hL,
|
||
|
double& hR);
|
||
|
|
||
|
private:
|
||
|
vtkGreedyTerrainDecimation(const vtkGreedyTerrainDecimation&) = delete;
|
||
|
void operator=(const vtkGreedyTerrainDecimation&) = delete;
|
||
|
};
|
||
|
|
||
|
#endif
|