public class SemiVirtualIncrementalTin extends Object implements IIncrementalTin
The counterpart to this class, IncrementalTin, uses a direct implementation of the quad-edge structure popularized by Guibas and Stolfi. While that approach leads to elegant code, the nature of the Java language (and object-oriented languages in general) results in relatively expensive memory requirements, approximately 244 bytes per vertex inserted into the TIN (counting the storage for both edges and vertices). Since it is common for many geophysical data sets to include multiple-millions of points, that memory use adds up fast.
This class reduces memory requirements by representing the edge-link relationships with internal integer arrays and numerical indexing rather than object references. By keeping the edge relationship data in "virtual form", the implementation reduces the memory use for the edges to about 120 bytes per vertex. The implementation is "semi-virtual" in that all data is still kept in core, but the amount of memory is reduced by a virtual representation of the edge structures.
Unfortunately, this reduction comes with a cost. In testing, the virtual implementation requires approximately 30 percent more runtime to process vertices than the direct implementation. Both implementations experience a degradation of throughput when the memory use approaches the maximum allowed by the JVM (specified on the command line using the -Xmx#### option). But since the virtual implementation uses half the memory of the direct implementation, the onset of degraded conditions when working with a fixed memory size can be pushed back considerably using the virtual implementation.
This class also dramatically reduces the number of objects that are used to represent the TIN. The IncrementalTIN class uses about 7.005 objects per vertex (including vertices and edges) while the virtual implementation uses only about 1.012. This reduction can be valuable in reducing the impact of garbage collection when processing large data sets..
The Bower-Watson algorithm for point insertion is discussed in Cheng, Siu-Wing; Dey, T.; Shewchuk, J. (2013) "Delaunay mesh generation", CRC Press, Boca Raton, FL. This is a challenging book that provides an overview of both 2D and solid TIN models. Jonathan Shewchuk is pretty much the expert on Delaunay Triangulations and his writings were a valuable resource in the creation of this class. You can also read Bowyer's and Watson's original papers both of which famously appeared in the same issue of the same journal in 1981. See Bowyer, A. (1981) "Computing Dirichlet tesselations", The Computer Journal" Vol 24, No 2., p. 162-166. and Watson, D. (1981) "Computing the N-dimensional tesselation with application to Voronoi Diagrams", The Computer Journal" Vol 24, No 2., p. 167-172.
The point-removal algorithm is due to Devillers. See Devillers, O. (2002), "On deletion in delaunay triangulations", International Journal of Computational Geometry & Applications 12.3 p. 123-2005.
The QuadEdge concept is based on the structure popularized by Guibas, L. and Stolfi, J. (1985) "Primitives for the manipulation of subdivisions and the computation of Voronoi diagrams" ACM Transactions on Graphics, 4(2), 1985, p. 75-123.
Constructor and Description |
---|
SemiVirtualIncrementalTin()
Constructs an incremental TIN using numerical thresholds appropriate
for the default nominal point spacing of 1 unit.
|
SemiVirtualIncrementalTin(double nominalPointSpacing)
Constructs an incremental TIN using numerical thresholds appropriate
for the specified nominal point spacing.
|
Modifier and Type | Method and Description |
---|---|
boolean |
add(List<Vertex> list,
IMonitorWithCancellation monitor)
Inserts a list of vertices into the collection of vertices managed by the
TIN.
|
boolean |
add(Vertex v)
Insert a vertex into the collection of vertices managed by
the TIN.
|
void |
addConstraints(List<IConstraint> constraints,
boolean restoreConformity)
Adds constraints to the TIN.
|
void |
clear()
Clears all internal state data of the TIN, preparing any allocated
resources for re-use.
|
TriangleCount |
countTriangles()
Performs a survey of the TIN to gather statistics about the triangle
formed during its construction.
|
void |
dispose()
Nullifies all internal data and references, preparing the
instance for garbage collection.
|
Iterable<IQuadEdge> |
edges()
Provides a convenience implementation
that can be used with a Java enhanced-loop statement to access the set
of edges that form the structure of the incremental TIN.
|
Rectangle2D |
getBounds()
Gets the bounds of the TIN.
|
IConstraint |
getConstraint(int index)
Gets the constraint associated with the index, or a null if
no such constraint exists.
|
List<IConstraint> |
getConstraints()
Gets a shallow copy of the list of constraints currently
stored in the TIN.
|
Iterator<IQuadEdge> |
getEdgeIterator()
Gets an iterator for stepping through the collection of edges
currently stored in the TIN.
|
List<IQuadEdge> |
getEdges()
Gets a list of edges currently allocated by an instance.
|
IIntegrityCheck |
getIntegrityCheck()
Gets an implementation of the integrity check interface suitable for
the referenced TIN implementation.
|
IConstraint |
getLinearConstraint(IQuadEdge edge)
Gets the linear constraint associated with the edge, if any.
|
int |
getMaximumEdgeAllocationIndex()
Gets the maximum index of the currently allocated edges.
|
IIncrementalTinNavigator |
getNavigator()
Gets a new instance of the IIncrementalTinNavigator interface.
|
INeighborEdgeLocator |
getNeighborEdgeLocator()
Gets a new instance of the INeighborEdgeLocator interface.
|
INeighborhoodPointsCollector |
getNeighborhoodPointsCollector()
Gets a new instance of a neighborhood points collector.
|
double |
getNominalPointSpacing()
Gets the nominal point spacing used to determine numerical thresholds
for various proximity and inclusion tests.
|
List<IQuadEdge> |
getPerimeter()
Gets a list of edges currently defining the perimeter of the TIN.
|
IConstraint |
getRegionConstraint(IQuadEdge edge)
Gets the region constraint associated with the edge, if any.
|
SemiVirtualEdge |
getStartingEdge()
Obtains an arbitrary edge to serve as the
start of a search or traversal operation.
|
int |
getSyntheticVertexCount()
Gets the number of synthetic vertices added to the TIN.
|
Thresholds |
getThresholds()
Gets the Thresholds object that is associated with this instance.
|
List<Vertex> |
getVertices()
Gets a list of vertices currently stored in the TIN.
|
boolean |
isBootstrapped()
Indicates whether the instance contains sufficient information
to represent a TIN.
|
void |
preAllocateEdges(int nVertices)
Allocates a number of vertices roughly sufficient to represent a TIN
containing the specified number of vertices.
|
void |
printDiagnostics(PrintStream ps)
Print statistics and diagnostic information collected during the
TIN construction process.
|
void |
printEdges(PrintStream ps)
Provides a diagnostic print out of the edges comprising the TIN.
|
boolean |
remove(Vertex vRemove)
Removes the specified vertex from the TIN.
|
void |
setResolutionRuleForMergedVertices(VertexMergerGroup.ResolutionRule resolutionRule)
Specifies a rule for interpreting the Z value of a group of vertices that
were merged due to being coincident, or nearly coincident.
|
Vertex |
splitEdge(IQuadEdge eInput,
double zSplit,
boolean restoreConformity)
Split an existing edge into two at the midpoint, using the
specified zSplit value as the z coordinate for the edge.
|
Iterable<SimpleTriangle> |
triangles()
Provides a convenience implementation
that can be used with a Java enhanced-loop statement to access the set
of SimpleTriangles implicit in the structure of the incremental TIN.
|
Iterable<Vertex> |
vertices()
Provides a convenience implementation
that can be used with a Java enhanced-loop statement to access the set
of vertices stored in an incremental TIN.
|
public SemiVirtualIncrementalTin()
public SemiVirtualIncrementalTin(double nominalPointSpacing)
Lidar applications sometimes refer to the point-spacing concept as "nominal pulse spacing", a term that reflects the origin of the data in a laser-based measuring system.
nominalPointSpacing
- the nominal distance between points.public boolean add(Vertex v)
add
in interface IIncrementalTin
v
- a valid vertexpublic boolean add(List<Vertex> list, IMonitorWithCancellation monitor)
In the bootstrap phase, three points are chosen at random from the vertex list to create the initial triangle for insertion. The initialization will make a small number of selection attempts and select the triangle with the largest number. In the event that this process does not find three points that are not a suitable choice (as when they are collinear or nearly collinear), the process will be repeated until a valid initial triangle is selected.
Thus, there is a small performance advantage in supplying the vertices using a list that can be accessed efficiently in a random order (see the discussion of the Java API for the List and java.util.RandomAccess interfaces). Once the initial triangle is established, the list will be traversed sequentially to build the TIN and random access considerations will no longer apply.
add
in interface IIncrementalTin
list
- a valid list of vertices to be added to the TIN.monitor
- an optional instance of a monitoring implementation;
null if not usedpublic void preAllocateEdges(int nVertices)
preAllocateEdges
in interface IIncrementalTin
nVertices
- the number of vertices expected to be added to the TIN.public Rectangle2D getBounds()
getBounds
in interface IIncrementalTin
public void printEdges(PrintStream ps)
printEdges
in interface IIncrementalTin
ps
- A valid print stream.public TriangleCount countTriangles()
countTriangles
in interface IIncrementalTin
public List<IQuadEdge> getPerimeter()
Warning: For efficiency purposes, the edges return by this routine are the same objects as those currently being used in the instance. Any modification of the edge objects will damage the TIN. Therefore, applications must not modify the edges returned by this method.
getPerimeter
in interface IIncrementalTin
public void printDiagnostics(PrintStream ps)
printDiagnostics
in interface IIncrementalTin
ps
- A valid instance of a PrintStream to receive the output.public List<IQuadEdge> getEdges()
Warning: For efficiency purposes, the edges return by this routine are the same objects as those currently being used in the instance. Any modification of the edge objects will damage the TIN. Therefore, applications must not modify the edges returned by this method.
getEdges
in interface IIncrementalTin
public Iterator<IQuadEdge> getEdgeIterator()
IIncrementalTin
Note that this loop produces only the "base side" of each edge. To access the counterpart (the side of the edge in the other direction), an application needs to access its dual using the edge's getDual() method.
Warning: For efficiency purposes, the edges returned by this routine are the same objects as those currently being used in the instance. Any modification of the edge objects will damage the TIN. Therefore, applications must not modify the edges returned by this method. Caution: For reasons of efficiency, the iterator does not offer any protection against concurrent modification. Therefore applications using this iterator must never modify the TIN during iteration.
getEdgeIterator
in interface IIncrementalTin
public Iterable<IQuadEdge> edges()
IIncrementalTin
For example, this method could be used in the following manner:
IIncremntal tin = // some implementation for(IQuadEdge e: tin.edges(){ // some processing logic }
Note that this loop produces only the "base side" of each edge. To access the counterpart (the side of the edge in the other direction), an application needs to access its dual using the edge's getDual() method.
Please see the API documentation for getEdgeIterator() for cautions regarding the use of this method.
edges
in interface IIncrementalTin
public int getMaximumEdgeAllocationIndex()
IIncrementalTin
Internally, Tinfour uses edge index values to manage edges in memory. The while there can be small gaps in the indexing sequence, this method provides a way of obtaining the absolute maximum value of currently allocated edges.
getMaximumEdgeAllocationIndex
in interface IIncrementalTin
public double getNominalPointSpacing()
Lidar applications sometimes refer to the point-spacing concept as "nominal pulse spacing", a term that reflects the origin of the data in a laser-based measuring system.
getNominalPointSpacing
in interface IIncrementalTin
public Thresholds getThresholds()
IIncrementalTin
getThresholds
in interface IIncrementalTin
public void dispose()
IIncrementalTin
dispose
in interface IIncrementalTin
public void clear()
IIncrementalTin
clear
in interface IIncrementalTin
public boolean isBootstrapped()
isBootstrapped
in interface IIncrementalTin
public boolean remove(Vertex vRemove)
At this time, this method does not handle the case where all vertices are removed from the TIN.
remove
in interface IIncrementalTin
vRemove
- the vertex to be removedpublic SemiVirtualEdge getStartingEdge()
public void setResolutionRuleForMergedVertices(VertexMergerGroup.ResolutionRule resolutionRule)
setResolutionRuleForMergedVertices
in interface IIncrementalTin
resolutionRule
- The rule to be used for interpreting merged vertices.public List<Vertex> getVertices()
getVertices
in interface IIncrementalTin
public INeighborEdgeLocator getNeighborEdgeLocator()
IIncrementalTin
This method is obsolete. Use getNavigator instead.
getNeighborEdgeLocator
in interface IIncrementalTin
public IIncrementalTinNavigator getNavigator()
IIncrementalTin
Instances observe the contract of the IProcessUsingTin interface in that they access the TIN on a read-only basis and may be used in parallel threads provided that the TIN is not modified.
getNavigator
in interface IIncrementalTin
public INeighborhoodPointsCollector getNeighborhoodPointsCollector()
IIncrementalTin
getNeighborhoodPointsCollector
in interface IIncrementalTin
public IIntegrityCheck getIntegrityCheck()
IIncrementalTin
getIntegrityCheck
in interface IIncrementalTin
public void addConstraints(List<IConstraint> constraints, boolean restoreConformity)
IIncrementalTin
Using Constraints
There are a number of important restrictions to the use of constraints. Constraints must only be added to the TIN once, after all other vertices have already been added. Furthermore, the addConstraint method can only be called once. Logic is implemented as a safety measure to ensure that these restrictions are not accidentally violated.
There are also important restrictions on the geometry of constraints. Most importantly, constraints must never intersect each other except at the endpoints of the segments that define them (i.e. segments in constraints must never cross each other). Due to the high cost of processing required to check that this restriction is observed, it is not directly enforced by the Tinfour implementations.
Restoring Conformity
When constraints are added to a Delaunay triangulation, they often violate the Delaunay criterion and result in a non-conforming mesh. The addConstraint method can optionally restore conformity by inserting synthetic points into the the constraint edges. The cost of this process is additional processing time and an increase in the number of points in the TIN.
When points are synthesized, it is necessary to interpolate a value for the z-coordinate. At this time, the specific interpolation process is undefined. The current Tinfour implementations use linear interpolation between constraint points. While no viable alternative approach is currently under consideration, the choice of interpolation method is subject to change in the future.
addConstraints
in interface IIncrementalTin
constraints
- a valid, potentially empty list.restoreConformity
- restores conformitypublic List<IConstraint> getConstraints()
IIncrementalTin
getConstraints
in interface IIncrementalTin
public IConstraint getConstraint(int index)
IIncrementalTin
getConstraint
in interface IIncrementalTin
index
- an arbitrary integer indexpublic IConstraint getRegionConstraint(IQuadEdge edge)
IIncrementalTin
getRegionConstraint
in interface IIncrementalTin
edge
- a valid edge instance.public IConstraint getLinearConstraint(IQuadEdge edge)
IIncrementalTin
getLinearConstraint
in interface IIncrementalTin
edge
- a valid edge instance.public int getSyntheticVertexCount()
IIncrementalTin
getSyntheticVertexCount
in interface IIncrementalTin
public Vertex splitEdge(IQuadEdge eInput, double zSplit, boolean restoreConformity)
IIncrementalTin
WARNING The restoreDelaunay feature is not yet implemented.
splitEdge
in interface IIncrementalTin
eInput
- a valid edgezSplit
- the z coordinate for the new vertexrestoreConformity
- restore Delaunay conformance after
insertion NOT YET IMPLEMENTEpublic Iterable<SimpleTriangle> triangles()
IIncrementalTin
For example, this method could be used in the following manner:
IIncremntal tin = // a valid instance for(SimpleTriangle t: tin.triangles(){ // some processing logic }
Please see the API documentation for SimpleTriangleIterator for cautions regarding the use of this method.
triangles
in interface IIncrementalTin
public Iterable<Vertex> vertices()
IIncrementalTin
For example, this method could be used in the following manner:
IIncremntal tin = // a valid instance for(Vertex v: tin.verticess(){ // some processing logic }
Please see the API documentation for VertexIterator for cautions regarding the use of this method.
vertices
in interface IIncrementalTin
Copyright © 2021. All rights reserved.