diff --git a/dist/Tinfour-1.0.jar b/dist/Tinfour-1.0.jar index c8577b79..7a2d3188 100644 Binary files a/dist/Tinfour-1.0.jar and b/dist/Tinfour-1.0.jar differ diff --git a/dist/TinfourViewer-1.0.jar b/dist/TinfourViewer-1.0.jar index 7a4523d9..c14151da 100644 Binary files a/dist/TinfourViewer-1.0.jar and b/dist/TinfourViewer-1.0.jar differ diff --git a/src/main/java/tinfour/voronoi/BoundedVoronoiBuildOptions.java b/src/main/java/tinfour/voronoi/BoundedVoronoiBuildOptions.java index 17d1d0ad..e05197b9 100644 --- a/src/main/java/tinfour/voronoi/BoundedVoronoiBuildOptions.java +++ b/src/main/java/tinfour/voronoi/BoundedVoronoiBuildOptions.java @@ -36,7 +36,7 @@ */ public class BoundedVoronoiBuildOptions { - protected boolean enableAdjustments = false; + protected boolean enableAdjustments; // The default adjustment value of 30 was chosen through trial and error. // A round number was chosen to reflect the fact that it is an arbitrary diff --git a/src/main/java/tinfour/voronoi/BoundedVoronoi.java b/src/main/java/tinfour/voronoi/BoundedVoronoiDiagram.java similarity index 94% rename from src/main/java/tinfour/voronoi/BoundedVoronoi.java rename to src/main/java/tinfour/voronoi/BoundedVoronoiDiagram.java index e5876f4b..bc64c822 100644 --- a/src/main/java/tinfour/voronoi/BoundedVoronoi.java +++ b/src/main/java/tinfour/voronoi/BoundedVoronoiDiagram.java @@ -57,8 +57,6 @@ import tinfour.common.Vertex; import tinfour.edge.EdgePool; import tinfour.edge.QuadEdge; -import tinfour.semivirtual.SemiVirtualIncrementalTin; -import tinfour.standard.IncrementalTin; import tinfour.utils.TinInstantiationUtility; import tinfour.utils.VertexColorizerKempe6; @@ -71,7 +69,7 @@ * This class is under development and is subject to minor * changes in its API and behavior. */ -public class BoundedVoronoi { +public class BoundedVoronoiDiagram { /** * The overall domain of the structure @@ -95,7 +93,7 @@ public class BoundedVoronoi { private double maxRadius = -1; - private BoundedVoronoi() { + private BoundedVoronoiDiagram() { // a private constructor to deter applications from // invoking the default constructor sampleBounds = null; @@ -111,7 +109,7 @@ private BoundedVoronoi() { * null to use defaults. * */ - public BoundedVoronoi(List vertexList, BoundedVoronoiBuildOptions options) { + public BoundedVoronoiDiagram(List vertexList, BoundedVoronoiBuildOptions options) { if (vertexList == null) { throw new IllegalArgumentException( "Null input not allowed for constructor"); @@ -176,7 +174,7 @@ public BoundedVoronoi(List vertexList, BoundedVoronoiBuildOptions option * @param delaunayTriangulation a valid instance of a Delaunay Triangulation * implementation. */ - public BoundedVoronoi(IIncrementalTin delaunayTriangulation) { + public BoundedVoronoiDiagram(IIncrementalTin delaunayTriangulation) { if (delaunayTriangulation == null) { throw new IllegalArgumentException( "Null input is not allowed for TIN"); @@ -316,8 +314,8 @@ private IQuadEdge liangBarsky(Vertex v0, Vertex v1) { } else { x = x0 + t0 * xDelta; y = y0 + t0 * yDelta; - z = computeZ(iBorder0, x, y); - p0 = new Vertex(x, y, z, v0.getIndex()); + z = computePerimeterParameter(iBorder0, x, y); + p0 = new PerimeterVertex(x, y, z, v0.getIndex()); p0.setSynthetic(true); } @@ -326,8 +324,8 @@ private IQuadEdge liangBarsky(Vertex v0, Vertex v1) { } else { x = x0 + t1 * xDelta; y = y0 + t1 * yDelta; - z = computeZ(iBorder1, x, y); - p1 = new Vertex(x, y, z, v1.getIndex()); + z = computePerimeterParameter(iBorder1, x, y); + p1 = new PerimeterVertex(x, y, z, v1.getIndex()); p1.setSynthetic(true); } @@ -335,7 +333,7 @@ private IQuadEdge liangBarsky(Vertex v0, Vertex v1) { } @SuppressWarnings("PMD.CollapsibleIfStatements") - private double computeZ(double x, double y) { + private double computePerimeterParameter(double x, double y) { if (y == ymin) { // bottom border range 0 to 1 if (xmin <= x && x <= xmax) { @@ -360,7 +358,7 @@ private double computeZ(double x, double y) { return Double.NaN; } - private double computeZ(int iBoarder, double x, double y) { + private double computePerimeterParameter(int iBoarder, double x, double y) { switch (iBoarder) { case 0: return (x - xmin) / (xmax - xmin); @@ -451,14 +449,14 @@ private void buildPerimeterRay(IQuadEdge e, Vertex[] center, IQuadEdge[] part) { y = t * uY + cY; if (t >= 0 && y0 <= y && y <= y1) { z = 4 - (y - y0) / (y1 - y0); // the left side, descending, z in [3,4] - Vertex v = new Vertex(x0, y, z, -vCenter.getIndex()); + Vertex v = new PerimeterVertex(x0, y, z, -vCenter.getIndex()); nBuild = insertRayVertex(nBuild, vBuild, tBuild, t, v); } t = (x1 - cX) / uX; y = t * uY + cY; if (t >= 0 && y0 <= y && y <= y1) { z = 1 + (y - y0) / (y1 - y0); // right side, ascending, z in [1,2] - Vertex v = new Vertex(x1, y, z, -vCenter.getIndex()); + Vertex v = new PerimeterVertex(x1, y, z, -vCenter.getIndex()); nBuild = insertRayVertex(nBuild, vBuild, tBuild, t, v); } } @@ -468,7 +466,7 @@ private void buildPerimeterRay(IQuadEdge e, Vertex[] center, IQuadEdge[] part) { x = t * uX + cX; if (t >= 0 && x0 <= x && x <= x1) { z = (x - x0) / (x1 - x0); // bottom side, ascending, z in [0,1] - Vertex v = new Vertex(x, y0, z, -vCenter.getIndex()); + Vertex v = new PerimeterVertex(x, y0, z, -vCenter.getIndex()); nBuild = insertRayVertex(nBuild, vBuild, tBuild, t, v); } @@ -476,7 +474,7 @@ private void buildPerimeterRay(IQuadEdge e, Vertex[] center, IQuadEdge[] part) { x = t * uX + cX; if (t >= 0 && x0 <= x && x <= x1) { z = 3 - (x - x0) / (x1 - x0); // top side, descending, z in [2,3] - Vertex v = new Vertex(x, y1, z, -vCenter.getIndex()); + Vertex v = new PerimeterVertex(x, y1, z, -vCenter.getIndex()); nBuild = insertRayVertex(nBuild, vBuild, tBuild, t, v); } } @@ -574,8 +572,16 @@ private void buildCenter(Circumcircle cCircle, IQuadEdge e, Vertex[] centers) { } double x = cCircle.getX(); double y = cCircle.getY(); - double z = computeZ(x, y); - Vertex v = new Vertex(x, y, z, mindex(e, f, r)); + // there is a low, but non-zero, probability that the center + // will lie on one of the perimeter edges. + double z = computePerimeterParameter(x, y); + Vertex v; + if (Double.isNaN(z)) { + v = new Vertex(x, y, z, mindex(e, f, r)); + } else { + v = new PerimeterVertex(x, y, z, mindex(e, f, r)); + } + centers[e.getIndex()] = v; centers[f.getIndex()] = v; centers[r.getIndex()] = v; @@ -594,15 +600,18 @@ private void buildStructure( IIncrementalTin tin, BoundedVoronoiBuildOptions pOptions) { - if (pOptions.enableAdjustments) { - if (tin instanceof IncrementalTin) { - ((IncrementalTin) tin).collaspsePerimeterTriangles( - pOptions.adjustmentThreshold); - } else if (tin instanceof SemiVirtualIncrementalTin) { - ((SemiVirtualIncrementalTin) tin).collaspsePerimeterTriangles( - pOptions.adjustmentThreshold); - } - } + + // The TIN classes' adjustment logic has a flaw, so it is supressed here + // pending a fix or permanent removal + //if (pOptions.enableAdjustments) { + // if (tin instanceof IncrementalTin) { + // ((IncrementalTin) tin).collaspsePerimeterTriangles( + // pOptions.adjustmentThreshold); + // } else if (tin instanceof SemiVirtualIncrementalTin) { + // ((SemiVirtualIncrementalTin) tin).collaspsePerimeterTriangles( + // pOptions.adjustmentThreshold); + // } + //} // The visited array tracks which of the TIN edges were // visited for various processes. It is used more than once. diff --git a/src/main/java/tinfour/voronoi/BoundedVoronoiDrawingUtility.java b/src/main/java/tinfour/voronoi/BoundedVoronoiDrawingUtility.java index c376067b..479c50e3 100644 --- a/src/main/java/tinfour/voronoi/BoundedVoronoiDrawingUtility.java +++ b/src/main/java/tinfour/voronoi/BoundedVoronoiDrawingUtility.java @@ -60,7 +60,7 @@ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public class BoundedVoronoiDrawingUtility { - private final BoundedVoronoi diagram; + private final BoundedVoronoiDiagram diagram; private final AffineTransform af; private final Rectangle2D bounds; @@ -100,7 +100,7 @@ public class BoundedVoronoiDrawingUtility { * defaults are to be used. */ public BoundedVoronoiDrawingUtility( - BoundedVoronoi diagram, + BoundedVoronoiDiagram diagram, int width, int height, int pad, diff --git a/src/main/java/tinfour/voronoi/BoundedVoronoiIntegrityCheck.java b/src/main/java/tinfour/voronoi/BoundedVoronoiIntegrityCheck.java index 981cc6d6..7e2fc35b 100644 --- a/src/main/java/tinfour/voronoi/BoundedVoronoiIntegrityCheck.java +++ b/src/main/java/tinfour/voronoi/BoundedVoronoiIntegrityCheck.java @@ -41,14 +41,14 @@ public class BoundedVoronoiIntegrityCheck { String message; - BoundedVoronoi lmv; + BoundedVoronoiDiagram lmv; /** * Constructs an instance of the integrity checker tied to the * specified instance. * @param BoundedVoronoi a valid, correctly populated instance */ - public BoundedVoronoiIntegrityCheck(BoundedVoronoi BoundedVoronoi) { + public BoundedVoronoiIntegrityCheck(BoundedVoronoiDiagram BoundedVoronoi) { lmv = BoundedVoronoi; message = null; } diff --git a/src/main/java/tinfour/voronoi/PerimeterVertex.java b/src/main/java/tinfour/voronoi/PerimeterVertex.java new file mode 100644 index 00000000..aa932904 --- /dev/null +++ b/src/main/java/tinfour/voronoi/PerimeterVertex.java @@ -0,0 +1,76 @@ +/* -------------------------------------------------------------------- + * Copyright 2018 Gary W. Lucas. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0A + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * --------------------------------------------------------------------- + */ + + /* + * ----------------------------------------------------------------------- + * + * Revision History: + * Date Name Description + * ------ --------- ------------------------------------------------- + * 09/2018 G. Lucas Initial implementation + * + * Notes: + * + * ----------------------------------------------------------------------- + */ +package tinfour.voronoi; + +import tinfour.common.Vertex; + +/** + * Extends the Vertex class to add perimeter parameter. + */ +class PerimeterVertex extends Vertex { + /** + * The perimeter parameter + */ + final double p; + + /** + * Construct a vertex at the specified horizontal Cartesian coordinates with + * a z value indicating the parameterized position along the rectangular + * bounds of the Voronoi Diagram. The parameter is a value in the + * range 0 ≤ z < 4. + * @param x the x Cartesian coordinate of the vertex + * @param y the y Cartesian coordinate of the vertex + * @param z the parameterized position, in range 0 to 4. + * @param index an arbitrary index value + */ + public PerimeterVertex(double x, double y, double z, int index){ + super(x, y, z, index); + this.p = z; + } + + /** + * Gets the perimeter parameter value for vertex. + * @return a valid double-precision value + */ + @Override + public double getZ(){ + return p; + } + + @Override + public String toString() { + if (this.isSynthetic()) { + return String.format("Pv %11.9f", p); + } else { + // the rare case of a circumcenter lying on the perimeter + return String.format("Pcc %11.9f, center %d", p, getIndex()); + } + } +} diff --git a/src/main/java/tinfour/voronoi/ThiessenPolygon.java b/src/main/java/tinfour/voronoi/ThiessenPolygon.java index d056f83a..3ad670cf 100644 --- a/src/main/java/tinfour/voronoi/ThiessenPolygon.java +++ b/src/main/java/tinfour/voronoi/ThiessenPolygon.java @@ -99,7 +99,7 @@ public double getArea() { } /** - * Gets the central vertex of the polygon. + * Gets the defining vertex of the polygon. * * @return the vertex */ @@ -142,6 +142,20 @@ public boolean isPointInPolygon(double x, double y) { public boolean isOpen(){ return open; } + + /** + * Gets the index element of the defining vertex for this polygon. + * The vertex index is under the control of the calling application + * and is not modified by the Voronoi classes. Note that the + * index of a vertex is not necessarily unique but left to the + * requirements of the application that constructs it. + * @return an integer value + */ + public int getIndex(){ + return vertex.getIndex(); + } + + @Override public String toString() { return String.format("ThiessenPolygon vertex=%s", vertex.getLabel()); diff --git a/src/test/java/tinfour/test/shapefile/ShapefileReader.java b/src/test/java/tinfour/test/shapefile/ShapefileReader.java index 13455193..7432fb68 100644 --- a/src/test/java/tinfour/test/shapefile/ShapefileReader.java +++ b/src/test/java/tinfour/test/shapefile/ShapefileReader.java @@ -76,8 +76,8 @@ public ShapefileReader(File file) throws IOException { } minX = raf.readDouble(); - maxX = raf.readDouble(); minY = raf.readDouble(); + maxX = raf.readDouble(); maxY = raf.readDouble(); minZ = raf.readDouble(); maxZ = raf.readDouble(); @@ -196,6 +196,19 @@ record = new ShapefileRecord(); + ", expected " + shapefileType.getTypeCode()); } switch (shapefileType) { + case Point: + // simple case, but we populate other record items for consistency + record.setSizes(1,1); + record.nParts = 1; + record.nPoints = 1; + record.partStart[1] = 1; + record.x0 = raf.readDouble(); + record.y0 = raf.readDouble(); + record.x1 = record.x0; + record.y1 = record.y0; + record.xyz[0] = record.x0; + record.xyz[1] = record.y0; + break; case PolyLineZ: case PolygonZ: { record.x0 = raf.readDouble();