diff --git a/README.md b/README.md index 4e9173170d..de57a08f3b 100644 --- a/README.md +++ b/README.md @@ -10,22 +10,20 @@ GeoSpark artifacts are hosted in Maven Central. You can add a Maven dependency w ``` groupId: org.datasyslab artifactId: geospark -version: 0.3.1 +version: 0.3.2 ``` -## Version information +## Version information ([Full List](https://github.com/DataSystemsLab/GeoSpark/wiki/GeoSpark-Full-Version-Release-notes)) | Version | Summary | |:----------------: |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0.3.2 | Functionality enhancement: 1. [JTSplus Spatial Objects](https://github.com/jiayuasu/JTSplus) now carry the original input data. Each object stores "UserData" and provides getter and setter. 2. Add a new SpatialRDD constructor to transform a regular data RDD to a spatial partitioned SpatialRDD. | | 0.3.1 | Bug fix: Support Apache Spark 2.X version, fix a bug which results in inaccurate results when doing join query, add more unit test cases | | 0.3 | Major updates: Significantly shorten query time on spatial join for skewed data; Support load balanced spatial partitioning methods (also serve as the global index); Optimize code for iterative spatial data mining | -| 0.2 | Improve code structure and refactor API | -| 0.1 | Support spatial range, join and Knn | -| Master branch | even with 0.3.1 | +| Master branch | even with 0.3.2 | | Spark 1.X branch | even with 0.3.1 but only supports Apache Spark 1.X | - ## How to get started (For Scala and Java developers) @@ -34,15 +32,15 @@ version: 0.3.1 1. Apache Spark 2.X releases (Apache Spark 1.X releases support available in GeoSpark for Spark 1.X branch) 2. JDK 1.7 -3. Compiled GeoSpark jar (Run 'mvn clean install' at source code folder or Download [pre-compiled GeoSpark jar](https://github.com/DataSystemsLab/GeoSpark/releases) under "Release" tag). -4. You might need to modify the dependencies in "POM.xml" and make it consistent with your environment. +3. You might need to modify the dependencies in "POM.xml" and make it consistent with your environment. Note: GeoSpark Master branch supports Apache Spark 2.X releases and GeoSpark for Spark 1.X branch supports Apache Spark 1.X releases. Please refer to the proper branch you need. ### How to use GeoSpark APIs in an interactive Spark shell (Scala) 1. Have your Spark cluster ready. -2. Run Spark shell with GeoSpark as a dependency. +2. Download [pre-compiled GeoSpark jar](https://github.com/DataSystemsLab/GeoSpark/releases) under "Release" tag. +3. Run Spark shell with GeoSpark as a dependency. ` ./bin/spark-shell --jars GeoSpark_COMPILED.jar @@ -53,8 +51,7 @@ Note: GeoSpark Master branch supports Apache Spark 2.X releases and GeoSpark for ### How to use GeoSpark APIs in a self-contained Spark application (Scala and Java) 1. Create your own Apache Spark project in Scala or Java -2. Download GeoSpark source code or download [pre-compiled GeoSpark jar](https://github.com/DataSystemsLab/GeoSpark/releases) under "Release" tag. -3. Put GeoSpark source code with your own code and compile together. Or add GeoSpark.jar into your local compilation dependency. +2. Add GeoSpark Maven coordinates into your project dependencies. 4. You can now use GeoSpark APIs in your Spark program! 5. Use spark-submit to submit your compiled self-contained Spark program. @@ -97,7 +94,7 @@ Two pairs of longitude and latitude present the vertexes lie on the diagonal of Each tuple contains unlimited points. -##Supported data format +## Supported data format GeoSpark supports Comma-Separated Values ("csv"), Tab-separated values ("tsv"), Well-Known Text ("wkt"), and GeoJSON ("geojson") as the input formats. Users only need to specify input format as Splitter and the start column (if necessary) of spatial info in one tuple as Offset when call Constructors. ## Important features @@ -131,6 +128,21 @@ Jia Yu, Jinxuan Wu, Mohamed Sarwat. ["GeoSpark: A Cluster Computing Framework fo GeoSaprk makes use of JTS Plus (An extended JTS Topology Suite Version 1.14) for some geometrical computations. Please refer to [JTS Topology Suite website](http://tsusiatsoftware.net/jts/main.html) and [JTS Plus](https://github.com/jiayuasu/JTSplus) for more details. + +## Thanks for the help from GeoSpark community +We appreciate the help and suggestions from the following GeoSpark users (List is increasing..): + +* @gaufung +* @lrojas94 +* @mdespriee +* @sabman +* @samchorlton +* @Tsarazin +* @TBuc +* ... + + + ## Contact ### Contributors @@ -140,7 +152,7 @@ Please refer to [JTS Topology Suite website](http://tsusiatsoftware.net/jts/main * [Mohamed Sarwat](http://faculty.engineering.asu.edu/sarwat/) (Email: msarwat@asu.edu) -###Project website +### Project website Please visit [GeoSpark project wesbite](http://geospark.datasyslab.org) for latest news and releases. ### DataSys Lab diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 33a0ad755b..07ec5e128b 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -2,10 +2,36 @@ 4.0.0 org.datasyslab - geospark-precompiled - GeoSpark - 0.3.1 - Spark-2.X + geospark + ${project.groupId}:${project.artifactId} + 0.3.2 + Geospatial extension for Apache Spark + http://geospark.datasyslab.org/ + + + Jia Yu + jiayu2@asu.edu + Arizona State University Data Systems Lab + http://www.datasyslab.org/ + + + Mohamed Sarwat + msarwat@asu.edu + Arizona State University Data Systems Lab + http://www.datasyslab.org/ + + + + + MIT license + https://opensource.org/licenses/MIT + + + + scm:git:git@github.com:DataSystemsLab/GeoSpark.git + scm:git:git@github.com:DataSystemsLab/GeoSpark.git + git@github.com:DataSystemsLab/GeoSpark.git + @@ -14,32 +40,24 @@ - maven-compiler-plugin - 3.1 - - 1.7 - 1.7 - - - - org.jacoco - jacoco-maven-plugin - 0.7.5.201505241946 + maven-source-plugin + attach-sources - prepare-agent - - - - report - test - - report + jar + + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + maven-shade-plugin 2.1 @@ -90,6 +108,202 @@ + + org.apache.spark + spark-core_2.11 + 2.0.1 + provided + + + avro-mapred + org.apache.avro + + + chill_2.11 + com.twitter + + + chill-java + com.twitter + + + xbean-asm5-shaded + org.apache.xbean + + + hadoop-client + org.apache.hadoop + + + spark-launcher_2.11 + org.apache.spark + + + spark-network-common_2.11 + org.apache.spark + + + spark-network-shuffle_2.11 + org.apache.spark + + + spark-unsafe_2.11 + org.apache.spark + + + jets3t + net.java.dev.jets3t + + + curator-recipes + org.apache.curator + + + javax.servlet-api + javax.servlet + + + commons-lang3 + org.apache.commons + + + commons-math3 + org.apache.commons + + + jsr305 + com.google.code.findbugs + + + slf4j-api + org.slf4j + + + jul-to-slf4j + org.slf4j + + + jcl-over-slf4j + org.slf4j + + + log4j + log4j + + + slf4j-log4j12 + org.slf4j + + + compress-lzf + com.ning + + + snappy-java + org.xerial.snappy + + + lz4 + net.jpountz.lz4 + + + RoaringBitmap + org.roaringbitmap + + + commons-net + commons-net + + + scala-library + org.scala-lang + + + json4s-jackson_2.11 + org.json4s + + + jersey-client + org.glassfish.jersey.core + + + jersey-common + org.glassfish.jersey.core + + + jersey-server + org.glassfish.jersey.core + + + jersey-container-servlet + org.glassfish.jersey.containers + + + jersey-container-servlet-core + org.glassfish.jersey.containers + + + mesos + org.apache.mesos + + + netty-all + io.netty + + + netty + io.netty + + + stream + com.clearspring.analytics + + + metrics-core + io.dropwizard.metrics + + + metrics-jvm + io.dropwizard.metrics + + + metrics-json + io.dropwizard.metrics + + + metrics-graphite + io.dropwizard.metrics + + + jackson-module-scala_2.11 + com.fasterxml.jackson.module + + + ivy + org.apache.ivy + + + oro + oro + + + pyrolite + net.razorvine + + + py4j + net.sf.py4j + + + spark-tags_2.11 + org.apache.spark + + + unused + org.spark-project.spark + + + UTF-8 diff --git a/doc/allclasses-frame.html b/doc/allclasses-frame.html index 32363abb70..73d0082756 100644 --- a/doc/allclasses-frame.html +++ b/doc/allclasses-frame.html @@ -2,9 +2,9 @@ - + All Classes - + @@ -12,8 +12,10 @@

All Classes

diff --git a/doc/org/datasyslab/geospark/spatialOperator/RangeQuery.html b/doc/org/datasyslab/geospark/spatialOperator/RangeQuery.html index 4fc075c865..409aed967c 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/RangeQuery.html +++ b/doc/org/datasyslab/geospark/spatialOperator/RangeQuery.html @@ -2,9 +2,9 @@ - + RangeQuery - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/class-use/DistanceJoin.html b/doc/org/datasyslab/geospark/spatialOperator/class-use/DistanceJoin.html index ceaf8d9548..a7c973bbe4 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/class-use/DistanceJoin.html +++ b/doc/org/datasyslab/geospark/spatialOperator/class-use/DistanceJoin.html @@ -2,9 +2,9 @@ - + Uses of Class org.datasyslab.geospark.spatialOperator.DistanceJoin - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/class-use/JoinQuery.html b/doc/org/datasyslab/geospark/spatialOperator/class-use/JoinQuery.html index d5f1341303..e813662ef7 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/class-use/JoinQuery.html +++ b/doc/org/datasyslab/geospark/spatialOperator/class-use/JoinQuery.html @@ -2,9 +2,9 @@ - + Uses of Class org.datasyslab.geospark.spatialOperator.JoinQuery - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/class-use/KNNQuery.html b/doc/org/datasyslab/geospark/spatialOperator/class-use/KNNQuery.html index 7533b69804..8fd2d148f3 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/class-use/KNNQuery.html +++ b/doc/org/datasyslab/geospark/spatialOperator/class-use/KNNQuery.html @@ -2,9 +2,9 @@ - + Uses of Class org.datasyslab.geospark.spatialOperator.KNNQuery - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/class-use/RangeQuery.html b/doc/org/datasyslab/geospark/spatialOperator/class-use/RangeQuery.html index 209d30128a..b3d88df5ee 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/class-use/RangeQuery.html +++ b/doc/org/datasyslab/geospark/spatialOperator/class-use/RangeQuery.html @@ -2,9 +2,9 @@ - + Uses of Class org.datasyslab.geospark.spatialOperator.RangeQuery - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/package-frame.html b/doc/org/datasyslab/geospark/spatialOperator/package-frame.html index 4727571426..574259e7cf 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/package-frame.html +++ b/doc/org/datasyslab/geospark/spatialOperator/package-frame.html @@ -2,9 +2,9 @@ - + org.datasyslab.geospark.spatialOperator - + diff --git a/doc/org/datasyslab/geospark/spatialOperator/package-summary.html b/doc/org/datasyslab/geospark/spatialOperator/package-summary.html index 4ac7ed0f12..59d9b44104 100644 --- a/doc/org/datasyslab/geospark/spatialOperator/package-summary.html +++ b/doc/org/datasyslab/geospark/spatialOperator/package-summary.html @@ -2,9 +2,9 @@ - + org.datasyslab.geospark.spatialOperator - + @@ -43,7 +43,7 @@
- + static PolygonRDD RangeQuery.SpatialRangeQueryUsingIndex(PolygonRDD polygonRDD, com.vividsolutions.jts.geom.Envelope envelope, diff --git a/doc/org/datasyslab/geospark/spatialRDD/class-use/RectangleRDD.html b/doc/org/datasyslab/geospark/spatialRDD/class-use/RectangleRDD.html index b46548d2d6..b8d2cb0436 100644 --- a/doc/org/datasyslab/geospark/spatialRDD/class-use/RectangleRDD.html +++ b/doc/org/datasyslab/geospark/spatialRDD/class-use/RectangleRDD.html @@ -2,9 +2,9 @@ - + Uses of Class org.datasyslab.geospark.spatialRDD.RectangleRDD - + diff --git a/doc/org/datasyslab/geospark/spatialRDD/package-frame.html b/doc/org/datasyslab/geospark/spatialRDD/package-frame.html index f8dca0dbaf..396c7ff85d 100644 --- a/doc/org/datasyslab/geospark/spatialRDD/package-frame.html +++ b/doc/org/datasyslab/geospark/spatialRDD/package-frame.html @@ -2,9 +2,9 @@ - + org.datasyslab.geospark.spatialRDD - + diff --git a/doc/org/datasyslab/geospark/spatialRDD/package-summary.html b/doc/org/datasyslab/geospark/spatialRDD/package-summary.html index b2e8c1acfe..2bd4e0a6cc 100644 --- a/doc/org/datasyslab/geospark/spatialRDD/package-summary.html +++ b/doc/org/datasyslab/geospark/spatialRDD/package-summary.html @@ -2,9 +2,9 @@ - + org.datasyslab.geospark.spatialRDD - + diff --git a/doc/org/datasyslab/geospark/spatialRDD/package-tree.html b/doc/org/datasyslab/geospark/spatialRDD/package-tree.html index ae20886212..e6753e50fa 100644 --- a/doc/org/datasyslab/geospark/spatialRDD/package-tree.html +++ b/doc/org/datasyslab/geospark/spatialRDD/package-tree.html @@ -2,9 +2,9 @@ - + org.datasyslab.geospark.spatialRDD Class Hierarchy - + diff --git a/doc/org/datasyslab/geospark/spatialRDD/package-use.html b/doc/org/datasyslab/geospark/spatialRDD/package-use.html index c5c54c0c18..55f8c31602 100644 --- a/doc/org/datasyslab/geospark/spatialRDD/package-use.html +++ b/doc/org/datasyslab/geospark/spatialRDD/package-use.html @@ -2,9 +2,9 @@ - + Uses of Package org.datasyslab.geospark.spatialRDD - + diff --git a/doc/overview-frame.html b/doc/overview-frame.html index f376096599..10a8d7d86d 100644 --- a/doc/overview-frame.html +++ b/doc/overview-frame.html @@ -2,9 +2,9 @@ - + Overview List - + @@ -13,6 +13,7 @@

Packages

diff --git a/doc/overview-summary.html b/doc/overview-summary.html index 531ac852b2..a5311e75b8 100644 --- a/doc/overview-summary.html +++ b/doc/overview-summary.html @@ -2,9 +2,9 @@ - + Overview - + @@ -78,10 +78,14 @@ -org.datasyslab.geospark.spatialOperator +org.datasyslab.geospark.geometryObjects   +org.datasyslab.geospark.spatialOperator +  + + org.datasyslab.geospark.spatialRDD   diff --git a/doc/overview-tree.html b/doc/overview-tree.html index 9adf3b9c03..c3f1447e4b 100644 --- a/doc/overview-tree.html +++ b/doc/overview-tree.html @@ -2,9 +2,9 @@ - + Class Hierarchy - + @@ -73,6 +73,7 @@

Hierarchy For All Packages

Package Hierarchies: @@ -82,8 +83,14 @@

Class Hierarchy

  • java.lang.Object
      +
    • org.datasyslab.geospark.geometryObjects.Circle (implements java.io.Serializable)
    • org.datasyslab.geospark.spatialRDD.CircleRDD (implements java.io.Serializable)
    • org.datasyslab.geospark.spatialOperator.DistanceJoin
    • +
    • com.vividsolutions.jts.geom.Envelope (implements java.lang.Comparable<T>, java.io.Serializable) + +
    • org.datasyslab.geospark.spatialOperator.JoinQuery (implements java.io.Serializable)
    • org.datasyslab.geospark.spatialOperator.KNNQuery (implements java.io.Serializable)
    • org.datasyslab.geospark.spatialRDD.PointRDD (implements java.io.Serializable)
    • diff --git a/doc/package-list b/doc/package-list index c390fd0c73..d1ab5d32d7 100644 --- a/doc/package-list +++ b/doc/package-list @@ -1,2 +1,3 @@ +org.datasyslab.geospark.geometryObjects org.datasyslab.geospark.spatialOperator org.datasyslab.geospark.spatialRDD diff --git a/doc/serialized-form.html b/doc/serialized-form.html index b59b58a4e8..8bb2f6fddd 100644 --- a/doc/serialized-form.html +++ b/doc/serialized-form.html @@ -2,9 +2,9 @@ - + Serialized Form - + @@ -75,6 +75,49 @@

      Serialized Form

      • +

        Package org.datasyslab.geospark.geometryObjects

        + +
      • +
      • Package org.datasyslab.geospark.spatialOperator

        • diff --git a/pom.xml b/pom.xml index 4344a15cac..010c3b613b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.datasyslab geospark - 0.3.1 + 0.3.2 ${project.groupId}:${project.artifactId} Geospatial extension for Apache Spark @@ -54,12 +54,17 @@ 2.0.1 provided + + + org.datasyslab + JTSplus + 0.1.0 + org.wololo jts2geojson 0.7.0 - com.vividsolutions @@ -70,8 +75,7 @@ - - + org.apache.maven.plugins maven-source-plugin @@ -84,8 +88,7 @@ - - + org.apache.maven.plugins @@ -97,26 +100,6 @@ - - org.jacoco - jacoco-maven-plugin - 0.7.5.201505241946 - - - - prepare-agent - - - - report - test - - report - - - - - org.apache.maven.plugins maven-shade-plugin diff --git a/src/main/java/com/vividsolutions/jts/JTSVersion.java b/src/main/java/com/vividsolutions/jts/JTSVersion.java deleted file mode 100644 index 15ebc021dc..0000000000 --- a/src/main/java/com/vividsolutions/jts/JTSVersion.java +++ /dev/null @@ -1,119 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts; - -/** - * JTS API version information. - *

          - * Versions consist of a 3-part version number: major.minor.patch - * An optional release status string may be present in the string version of - * the version. - * - * @version 1.7 - */ -public class JTSVersion { - - /** - * The current version number of the JTS API. - */ - public static final JTSVersion CURRENT_VERSION = new JTSVersion(); - - /** - * The major version number. - */ - public static final int MAJOR = 1; - - /** - * The minor version number. - */ - public static final int MINOR = 14; - - /** - * The patch version number. - */ - public static final int PATCH = 0; - - /** - * An optional string providing further release info (such as "alpha 1"); - */ - private static final String releaseInfo = ""; - - /** - * Prints the current JTS version to stdout. - * - * @param args the command-line arguments (none are required). - */ - public static void main(String[] args) - { - System.out.println(CURRENT_VERSION); - } - - private JTSVersion() { - } - - /** - * Gets the major number of the release version. - * - * @return the major number of the release version. - */ - public int getMajor() { return MAJOR; } - - /** - * Gets the minor number of the release version. - * - * @return the minor number of the release version. - */ - public int getMinor() { return MINOR; } - - /** - * Gets the patch number of the release version. - * - * @return the patch number of the release version. - */ - public int getPatch() { return PATCH; } - - /** - * Gets the full version number, suitable for display. - * - * @return the full version number, suitable for display. - */ - public String toString() - { - String ver = MAJOR + "." + MINOR + "." + PATCH; - if (releaseInfo != null && releaseInfo.length() > 0) - return ver + " " + releaseInfo; - return ver; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/Angle.java b/src/main/java/com/vividsolutions/jts/algorithm/Angle.java deleted file mode 100644 index 6c56e21350..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/Angle.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.algorithm.CGAlgorithms; - -/** - * Utility functions for working with angles. - * Unless otherwise noted, methods in this class express angles in radians. - */ -public class Angle -{ - public static final double PI_TIMES_2 = 2.0 * Math.PI; - public static final double PI_OVER_2 = Math.PI / 2.0; - public static final double PI_OVER_4 = Math.PI / 4.0; - - /** Constant representing counterclockwise orientation */ - public static final int COUNTERCLOCKWISE = CGAlgorithms.COUNTERCLOCKWISE; - - /** Constant representing clockwise orientation */ - public static final int CLOCKWISE = CGAlgorithms.CLOCKWISE; - - /** Constant representing no orientation */ - public static final int NONE = CGAlgorithms.COLLINEAR; - - /** - * Converts from radians to degrees. - * @param radians an angle in radians - * @return the angle in degrees - */ - public static double toDegrees(double radians) { - return (radians * 180) / (Math.PI); - } - - /** - * Converts from degrees to radians. - * - * @param angleDegrees an angle in degrees - * @return the angle in radians - */ - public static double toRadians(double angleDegrees) { - return (angleDegrees * Math.PI) / 180.0; - } - - - /** - * Returns the angle of the vector from p0 to p1, - * relative to the positive X-axis. - * The angle is normalized to be in the range [ -Pi, Pi ]. - * - * @return the normalized angle (in radians) that p0-p1 makes with the positive x-axis. - */ - public static double angle(Coordinate p0, Coordinate p1) { - double dx = p1.x - p0.x; - double dy = p1.y - p0.y; - return Math.atan2(dy, dx); - } - - /** - * Returns the angle that the vector from (0,0) to p, - * relative to the positive X-axis. - * The angle is normalized to be in the range ( -Pi, Pi ]. - * - * @return the normalized angle (in radians) that p makes with the positive x-axis. - */ - public static double angle(Coordinate p) { - return Math.atan2(p.y, p.x); - } - - - /** - * Tests whether the angle between p0-p1-p2 is acute. - * An angle is acute if it is less than 90 degrees. - *

          - * Note: this implementation is not precise (determistic) for angles very close to 90 degrees. - * - * @param p0 an endpoint of the angle - * @param p1 the base of the angle - * @param p2 the other endpoint of the angle - */ - public static boolean isAcute(Coordinate p0, Coordinate p1, Coordinate p2) - { - // relies on fact that A dot B is positive iff A ang B is acute - double dx0 = p0.x - p1.x; - double dy0 = p0.y - p1.y; - double dx1 = p2.x - p1.x; - double dy1 = p2.y - p1.y; - double dotprod = dx0 * dx1 + dy0 * dy1; - return dotprod > 0; - } - - /** - * Tests whether the angle between p0-p1-p2 is obtuse. - * An angle is obtuse if it is greater than 90 degrees. - *

          - * Note: this implementation is not precise (determistic) for angles very close to 90 degrees. - * - * @param p0 an endpoint of the angle - * @param p1 the base of the angle - * @param p2 the other endpoint of the angle - */ - public static boolean isObtuse(Coordinate p0, Coordinate p1, Coordinate p2) - { - // relies on fact that A dot B is negative iff A ang B is obtuse - double dx0 = p0.x - p1.x; - double dy0 = p0.y - p1.y; - double dx1 = p2.x - p1.x; - double dy1 = p2.y - p1.y; - double dotprod = dx0 * dx1 + dy0 * dy1; - return dotprod < 0; - } - - /** - * Returns the unoriented smallest angle between two vectors. - * The computed angle will be in the range [0, Pi). - * - * @param tip1 the tip of one vector - * @param tail the tail of each vector - * @param tip2 the tip of the other vector - * @return the angle between tail-tip1 and tail-tip2 - */ - public static double angleBetween(Coordinate tip1, Coordinate tail, - Coordinate tip2) { - double a1 = angle(tail, tip1); - double a2 = angle(tail, tip2); - - return diff(a1, a2); - } - - /** - * Returns the oriented smallest angle between two vectors. - * The computed angle will be in the range (-Pi, Pi]. - * A positive result corresponds to a counterclockwise - * (CCW) rotation - * from v1 to v2; - * a negative result corresponds to a clockwise (CW) rotation; - * a zero result corresponds to no rotation. - * - * @param tip1 the tip of v1 - * @param tail the tail of each vector - * @param tip2 the tip of v2 - * @return the angle between v1 and v2, relative to v1 - */ - public static double angleBetweenOriented(Coordinate tip1, Coordinate tail, - Coordinate tip2) - { - double a1 = angle(tail, tip1); - double a2 = angle(tail, tip2); - double angDel = a2 - a1; - - // normalize, maintaining orientation - if (angDel <= -Math.PI) - return angDel + PI_TIMES_2; - if (angDel > Math.PI) - return angDel - PI_TIMES_2; - return angDel; - } - - /** - * Computes the interior angle between two segments of a ring. The ring is - * assumed to be oriented in a clockwise direction. The computed angle will be - * in the range [0, 2Pi] - * - * @param p0 - * a point of the ring - * @param p1 - * the next point of the ring - * @param p2 - * the next point of the ring - * @return the interior angle based at p1 - */ - public static double interiorAngle(Coordinate p0, Coordinate p1, Coordinate p2) - { - double anglePrev = Angle.angle(p1, p0); - double angleNext = Angle.angle(p1, p2); - return Math.abs(angleNext - anglePrev); - } - - /** - * Returns whether an angle must turn clockwise or counterclockwise - * to overlap another angle. - * - * @param ang1 an angle (in radians) - * @param ang2 an angle (in radians) - * @return whether a1 must turn CLOCKWISE, COUNTERCLOCKWISE or NONE to - * overlap a2. - */ - public static int getTurn(double ang1, double ang2) { - double crossproduct = Math.sin(ang2 - ang1); - - if (crossproduct > 0) { - return COUNTERCLOCKWISE; - } - if (crossproduct < 0) { - return CLOCKWISE; - } - return NONE; - } - - /** - * Computes the normalized value of an angle, which is the - * equivalent angle in the range ( -Pi, Pi ]. - * - * @param angle the angle to normalize - * @return an equivalent angle in the range (-Pi, Pi] - */ - public static double normalize(double angle) - { - while (angle > Math.PI) - angle -= PI_TIMES_2; - while (angle <= -Math.PI) - angle += PI_TIMES_2; - return angle; - } - - /** - * Computes the normalized positive value of an angle, which is the - * equivalent angle in the range [ 0, 2*Pi ). - * E.g.: - *

            - *
          • normalizePositive(0.0) = 0.0 - *
          • normalizePositive(-PI) = PI - *
          • normalizePositive(-2PI) = 0.0 - *
          • normalizePositive(-3PI) = PI - *
          • normalizePositive(-4PI) = 0 - *
          • normalizePositive(PI) = PI - *
          • normalizePositive(2PI) = 0.0 - *
          • normalizePositive(3PI) = PI - *
          • normalizePositive(4PI) = 0.0 - *
          - * - * @param angle the angle to normalize, in radians - * @return an equivalent positive angle - */ - public static double normalizePositive(double angle) - { - if (angle < 0.0) { - while (angle < 0.0) - angle += PI_TIMES_2; - // in case round-off error bumps the value over - if (angle >= PI_TIMES_2) - angle = 0.0; - } - else { - while (angle >= PI_TIMES_2) - angle -= PI_TIMES_2; - // in case round-off error bumps the value under - if (angle < 0.0) - angle = 0.0; - } - return angle; - } - - /** - * Computes the unoriented smallest difference between two angles. - * The angles are assumed to be normalized to the range [-Pi, Pi]. - * The result will be in the range [0, Pi]. - * - * @param ang1 the angle of one vector (in [-Pi, Pi] ) - * @param ang2 the angle of the other vector (in range [-Pi, Pi] ) - * @return the angle (in radians) between the two vectors (in range [0, Pi] ) - */ - public static double diff(double ang1, double ang2) { - double delAngle; - - if (ang1 < ang2) { - delAngle = ang2 - ang1; - } else { - delAngle = ang1 - ang2; - } - - if (delAngle > Math.PI) { - delAngle = (2 * Math.PI) - delAngle; - } - - return delAngle; - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java b/src/main/java/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java deleted file mode 100644 index 631a73a4b3..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * An interface for rules which determine whether node points - * which are in boundaries of {@link Lineal} geometry components - * are in the boundary of the parent geometry collection. - * The SFS specifies a single kind of boundary node rule, - * the {@link Mod2BoundaryNodeRule} rule. - * However, other kinds of Boundary Node Rules are appropriate - * in specific situations (for instance, linear network topology - * usually follows the {@link EndPointBoundaryNodeRule}.) - * Some JTS operations - * (such as {@link RelateOp}, {@link BoundaryOp} and {@link IsSimpleOp}) - * allow the BoundaryNodeRule to be specified, - * and respect the supplied rule when computing the results of the operation. - *

          - * An example use case for a non-SFS-standard Boundary Node Rule is - * that of checking that a set of {@link LineString}s have - * valid linear network topology, when turn-arounds are represented - * as closed rings. In this situation, the entry road to the - * turn-around is only valid when it touches the turn-around ring - * at the single (common) endpoint. This is equivalent - * to requiring the set of LineStrings to be - * simple under the {@link EndPointBoundaryNodeRule}. - * The SFS-standard {@link Mod2BoundaryNodeRule} is not - * sufficient to perform this test, since it - * states that closed rings have no boundary points. - *

          - * This interface and its subclasses follow the Strategy design pattern. - * - * @author Martin Davis - * @version 1.7 - * - * @see RelateOp - * @see BoundaryOp - * @see IsSimpleOp - * @see PointLocator - */ -public interface BoundaryNodeRule -{ - - /** - * Tests whether a point that lies in boundaryCount - * geometry component boundaries is considered to form part of the boundary - * of the parent geometry. - * - * @param boundaryCount the number of component boundaries that this point occurs in - * @return true if points in this number of boundaries lie in the parent boundary - */ - boolean isInBoundary(int boundaryCount); - - /** - * The Mod-2 Boundary Node Rule (which is the rule specified in the OGC SFS). - * @see Mod2BoundaryNodeRule - */ - public static final BoundaryNodeRule MOD2_BOUNDARY_RULE = new Mod2BoundaryNodeRule(); - - /** - * The Endpoint Boundary Node Rule. - * @see EndPointBoundaryNodeRule - */ - public static final BoundaryNodeRule ENDPOINT_BOUNDARY_RULE = new EndPointBoundaryNodeRule(); - - /** - * The MultiValent Endpoint Boundary Node Rule. - * @see MultiValentEndPointBoundaryNodeRule - */ - public static final BoundaryNodeRule MULTIVALENT_ENDPOINT_BOUNDARY_RULE = new MultiValentEndPointBoundaryNodeRule(); - - /** - * The Monovalent Endpoint Boundary Node Rule. - * @see MonoValentEndPointBoundaryNodeRule - */ - public static final BoundaryNodeRule MONOVALENT_ENDPOINT_BOUNDARY_RULE = new MonoValentEndPointBoundaryNodeRule(); - - /** - * The Boundary Node Rule specified by the OGC Simple Features Specification, - * which is the same as the Mod-2 rule. - * @see Mod2BoundaryNodeRule - */ - public static final BoundaryNodeRule OGC_SFS_BOUNDARY_RULE = MOD2_BOUNDARY_RULE; - - /** - * A {@link BoundaryNodeRule} specifies that points are in the - * boundary of a lineal geometry iff - * the point lies on the boundary of an odd number - * of components. - * Under this rule {@link LinearRing}s and closed - * {@link LineString}s have an empty boundary. - *

          - * This is the rule specified by the OGC SFS, - * and is the default rule used in JTS. - * - * @author Martin Davis - * @version 1.7 - */ - public static class Mod2BoundaryNodeRule - implements BoundaryNodeRule - { - public boolean isInBoundary(int boundaryCount) - { - // the "Mod-2 Rule" - return boundaryCount % 2 == 1; - } - } - - /** - * A {@link BoundaryNodeRule} which specifies that any points which are endpoints - * of lineal components are in the boundary of the - * parent geometry. - * This corresponds to the "intuitive" topological definition - * of boundary. - * Under this rule {@link LinearRing}s have a non-empty boundary - * (the common endpoint of the underlying LineString). - *

          - * This rule is useful when dealing with linear networks. - * For example, it can be used to check - * whether linear networks are correctly noded. - * The usual network topology constraint is that linear segments may touch only at endpoints. - * In the case of a segment touching a closed segment (ring) at one point, - * the Mod2 rule cannot distinguish between the permitted case of touching at the - * node point and the invalid case of touching at some other interior (non-node) point. - * The EndPoint rule does distinguish between these cases, - * so is more appropriate for use. - * - * @author Martin Davis - * @version 1.7 - */ - public static class EndPointBoundaryNodeRule - implements BoundaryNodeRule - { - public boolean isInBoundary(int boundaryCount) - { - return boundaryCount > 0; - } - } - - /** - * A {@link BoundaryNodeRule} which determines that only - * endpoints with valency greater than 1 are on the boundary. - * This corresponds to the boundary of a {@link MultiLineString} - * being all the "attached" endpoints, but not - * the "unattached" ones. - * - * @author Martin Davis - * @version 1.7 - */ - public static class MultiValentEndPointBoundaryNodeRule - implements BoundaryNodeRule - { - public boolean isInBoundary(int boundaryCount) - { - return boundaryCount > 1; - } - } - - /** - * A {@link BoundaryNodeRule} which determines that only - * endpoints with valency of exactly 1 are on the boundary. - * This corresponds to the boundary of a {@link MultiLineString} - * being all the "unattached" endpoints. - * - * @author Martin Davis - * @version 1.7 - */ - public static class MonoValentEndPointBoundaryNodeRule - implements BoundaryNodeRule - { - public boolean isInBoundary(int boundaryCount) - { - return boundaryCount == 1; - } - } - - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms.java b/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms.java deleted file mode 100644 index c54bdadfa3..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms.java +++ /dev/null @@ -1,595 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Location; -import com.vividsolutions.jts.math.MathUtil; - -/** - * Specifies and implements various fundamental Computational Geometric - * algorithms. The algorithms supplied in this class are robust for - * double-precision floating point. - * - * @version 1.7 - */ -public class CGAlgorithms -{ - - /** - * A value that indicates an orientation of clockwise, or a right turn. - */ - public static final int CLOCKWISE = -1; - - /** - * A value that indicates an orientation of clockwise, or a right turn. - */ - public static final int RIGHT = CLOCKWISE; - - /** - * A value that indicates an orientation of counterclockwise, or a left turn. - */ - public static final int COUNTERCLOCKWISE = 1; - - /** - * A value that indicates an orientation of counterclockwise, or a left turn. - */ - public static final int LEFT = COUNTERCLOCKWISE; - - /** - * A value that indicates an orientation of collinear, or no turn (straight). - */ - public static final int COLLINEAR = 0; - - /** - * A value that indicates an orientation of collinear, or no turn (straight). - */ - public static final int STRAIGHT = COLLINEAR; - - /** - * Returns the index of the direction of the point q relative to - * a vector specified by p1-p2. - * - * @param p1 the origin point of the vector - * @param p2 the final point of the vector - * @param q the point to compute the direction to - * - * @return 1 if q is counter-clockwise (left) from p1-p2 - * @return -1 if q is clockwise (right) from p1-p2 - * @return 0 if q is collinear with p1-p2 - */ - public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) - { - /** - * MD - 9 Aug 2010 It seems that the basic algorithm is slightly orientation - * dependent, when computing the orientation of a point very close to a - * line. This is possibly due to the arithmetic in the translation to the - * origin. - * - * For instance, the following situation produces identical results in spite - * of the inverse orientation of the line segment: - * - * Coordinate p0 = new Coordinate(219.3649559090992, 140.84159161824724); - * Coordinate p1 = new Coordinate(168.9018919682399, -5.713787599646864); - * - * Coordinate p = new Coordinate(186.80814046338352, 46.28973405831556); int - * orient = orientationIndex(p0, p1, p); int orientInv = - * orientationIndex(p1, p0, p); - * - * A way to force consistent results is to normalize the orientation of the - * vector using the following code. However, this may make the results of - * orientationIndex inconsistent through the triangle of points, so it's not - * clear this is an appropriate patch. - * - */ - return CGAlgorithmsDD.orientationIndex(p1, p2, q); - // testing only - //return ShewchuksDeterminant.orientationIndex(p1, p2, q); - // previous implementation - not quite fully robust - //return RobustDeterminant.orientationIndex(p1, p2, q); - - } - - public CGAlgorithms() - { - } - - /** - * Tests whether a point lies inside or on a ring. The ring may be oriented in - * either direction. A point lying exactly on the ring boundary is considered - * to be inside the ring. - *

          - * This method does not first check the point against the envelope of - * the ring. - * - * @param p - * point to check for ring inclusion - * @param ring - * an array of coordinates representing the ring (which must have - * first point identical to last point) - * @return true if p is inside ring - * - * @see locatePointInRing - */ - public static boolean isPointInRing(Coordinate p, Coordinate[] ring) - { - return locatePointInRing(p, ring) != Location.EXTERIOR; - } - - /** - * Determines whether a point lies in the interior, on the boundary, or in the - * exterior of a ring. The ring may be oriented in either direction. - *

          - * This method does not first check the point against the envelope of - * the ring. - * - * @param p - * point to check for ring inclusion - * @param ring - * an array of coordinates representing the ring (which must have - * first point identical to last point) - * @return the {@link Location} of p relative to the ring - */ - public static int locatePointInRing(Coordinate p, Coordinate[] ring) - { - return RayCrossingCounter.locatePointInRing(p, ring); - } - - /** - * Tests whether a point lies on the line segments defined by a list of - * coordinates. - * - * @return true if the point is a vertex of the line or lies in the interior - * of a line segment in the linestring - */ - public static boolean isOnLine(Coordinate p, Coordinate[] pt) - { - LineIntersector lineIntersector = new RobustLineIntersector(); - for (int i = 1; i < pt.length; i++) { - Coordinate p0 = pt[i - 1]; - Coordinate p1 = pt[i]; - lineIntersector.computeIntersection(p, p0, p1); - if (lineIntersector.hasIntersection()) { - return true; - } - } - return false; - } - - /** - * Computes whether a ring defined by an array of {@link Coordinate}s is - * oriented counter-clockwise. - *

            - *
          • The list of points is assumed to have the first and last points equal. - *
          • This will handle coordinate lists which contain repeated points. - *
          - * This algorithm is only guaranteed to work with valid rings. If the - * ring is invalid (e.g. self-crosses or touches), the computed result may not - * be correct. - * - * @param ring - * an array of Coordinates forming a ring - * @return true if the ring is oriented counter-clockwise. - * @throws IllegalArgumentException - * if there are too few points to determine orientation (< 4) - */ - public static boolean isCCW(Coordinate[] ring) - { - // # of points without closing endpoint - int nPts = ring.length - 1; - // sanity check - if (nPts < 3) - throw new IllegalArgumentException( - "Ring has fewer than 4 points, so orientation cannot be determined"); - - // find highest point - Coordinate hiPt = ring[0]; - int hiIndex = 0; - for (int i = 1; i <= nPts; i++) { - Coordinate p = ring[i]; - if (p.y > hiPt.y) { - hiPt = p; - hiIndex = i; - } - } - - // find distinct point before highest point - int iPrev = hiIndex; - do { - iPrev = iPrev - 1; - if (iPrev < 0) - iPrev = nPts; - } while (ring[iPrev].equals2D(hiPt) && iPrev != hiIndex); - - // find distinct point after highest point - int iNext = hiIndex; - do { - iNext = (iNext + 1) % nPts; - } while (ring[iNext].equals2D(hiPt) && iNext != hiIndex); - - Coordinate prev = ring[iPrev]; - Coordinate next = ring[iNext]; - - /** - * This check catches cases where the ring contains an A-B-A configuration - * of points. This can happen if the ring does not contain 3 distinct points - * (including the case where the input array has fewer than 4 elements), or - * it contains coincident line segments. - */ - if (prev.equals2D(hiPt) || next.equals2D(hiPt) || prev.equals2D(next)) - return false; - - int disc = computeOrientation(prev, hiPt, next); - - /** - * If disc is exactly 0, lines are collinear. There are two possible cases: - * (1) the lines lie along the x axis in opposite directions (2) the lines - * lie on top of one another - * - * (1) is handled by checking if next is left of prev ==> CCW (2) will never - * happen if the ring is valid, so don't check for it (Might want to assert - * this) - */ - boolean isCCW = false; - if (disc == 0) { - // poly is CCW if prev x is right of next x - isCCW = (prev.x > next.x); - } - else { - // if area is positive, points are ordered CCW - isCCW = (disc > 0); - } - return isCCW; - } - - /** - * Computes the orientation of a point q to the directed line segment p1-p2. - * The orientation of a point relative to a directed line segment indicates - * which way you turn to get to q after travelling from p1 to p2. - * - * @param p1 the first vertex of the line segment - * @param p2 the second vertex of the line segment - * @param q the point to compute the relative orientation of - * @return 1 if q is counter-clockwise from p1-p2, - * or -1 if q is clockwise from p1-p2, - * or 0 if q is collinear with p1-p2 - */ - public static int computeOrientation(Coordinate p1, Coordinate p2, - Coordinate q) - { - return orientationIndex(p1, p2, q); - } - - /** - * Computes the distance from a point p to a line segment AB - * - * Note: NON-ROBUST! - * - * @param p - * the point to compute the distance for - * @param A - * one point of the line - * @param B - * another point of the line (must be different to A) - * @return the distance from p to line segment AB - */ - public static double distancePointLine(Coordinate p, Coordinate A, - Coordinate B) - { - // if start = end, then just compute distance to one of the endpoints - if (A.x == B.x && A.y == B.y) - return p.distance(A); - - // otherwise use comp.graphics.algorithms Frequently Asked Questions method - /* - * (1) r = AC dot AB - * --------- - * ||AB||^2 - * - * r has the following meaning: - * r=0 P = A - * r=1 P = B - * r<0 P is on the backward extension of AB - * r>1 P is on the forward extension of AB - * 0= 1.0) - return p.distance(B); - - /* - * (2) s = (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - * ----------------------------- - * L^2 - * - * Then the distance from C to P = |s|*L. - * - * This is the same calculation as {@link #distancePointLinePerpendicular}. - * Unrolled here for performance. - */ - double s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) - / len2; - return Math.abs(s) * Math.sqrt(len2); - } - - /** - * Computes the perpendicular distance from a point p to the (infinite) line - * containing the points AB - * - * @param p - * the point to compute the distance for - * @param A - * one point of the line - * @param B - * another point of the line (must be different to A) - * @return the distance from p to line AB - */ - public static double distancePointLinePerpendicular(Coordinate p, - Coordinate A, Coordinate B) - { - // use comp.graphics.algorithms Frequently Asked Questions method - /* - * (2) s = (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - * ----------------------------- - * L^2 - * - * Then the distance from C to P = |s|*L. - */ - double len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y); - double s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) - / len2; - - return Math.abs(s) * Math.sqrt(len2); - } - - /** - * Computes the distance from a point to a sequence of line segments. - * - * @param p - * a point - * @param line - * a sequence of contiguous line segments defined by their vertices - * @return the minimum distance between the point and the line segments - */ - public static double distancePointLine(Coordinate p, Coordinate[] line) - { - if (line.length == 0) - throw new IllegalArgumentException( - "Line array must contain at least one vertex"); - // this handles the case of length = 1 - double minDistance = p.distance(line[0]); - for (int i = 0; i < line.length - 1; i++) { - double dist = CGAlgorithms.distancePointLine(p, line[i], line[i + 1]); - if (dist < minDistance) { - minDistance = dist; - } - } - return minDistance; - } - - /** - * Computes the distance from a line segment AB to a line segment CD - * - * Note: NON-ROBUST! - * - * @param A - * a point of one line - * @param B - * the second point of (must be different to A) - * @param C - * one point of the line - * @param D - * another point of the line (must be different to A) - */ - public static double distanceLineLine(Coordinate A, Coordinate B, - Coordinate C, Coordinate D) - { - // check for zero-length segments - if (A.equals(B)) - return distancePointLine(A, C, D); - if (C.equals(D)) - return distancePointLine(D, A, B); - - // AB and CD are line segments - /* - * from comp.graphics.algo - * - * Solving the above for r and s yields - * - * (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) - * r = ----------------------------- (eqn 1) - * (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - * - * (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - * s = ----------------------------- (eqn 2) - * (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - * - * Let P be the position vector of the - * intersection point, then - * P=A+r(B-A) or - * Px=Ax+r(Bx-Ax) - * Py=Ay+r(By-Ay) - * By examining the values of r & s, you can also determine some other limiting - * conditions: - * If 0<=r<=1 & 0<=s<=1, intersection exists - * r<0 or r>1 or s<0 or s>1 line segments do not intersect - * If the denominator in eqn 1 is zero, AB & CD are parallel - * If the numerator in eqn 1 is also zero, AB & CD are collinear. - */ - - boolean noIntersection = false; - if (! Envelope.intersects(A, B, C, D)) { - noIntersection = true; - } - else { - double denom = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x); - - if (denom == 0) { - noIntersection = true; - } - else { - double r_num = (A.y - C.y) * (D.x - C.x) - (A.x - C.x) * (D.y - C.y); - double s_num = (A.y - C.y) * (B.x - A.x) - (A.x - C.x) * (B.y - A.y); - - double s = s_num / denom; - double r = r_num / denom; - - if ((r < 0) || (r > 1) || (s < 0) || (s > 1)) { - noIntersection = true; - } - } - } - if (noIntersection) { - return MathUtil.min( - distancePointLine(A, C, D), - distancePointLine(B, C, D), - distancePointLine(C, A, B), - distancePointLine(D, A, B)); - } - // segments intersect - return 0.0; - } - - /** - * Computes the signed area for a ring. The signed area is positive if the - * ring is oriented CW, negative if the ring is oriented CCW, and zero if the - * ring is degenerate or flat. - * - * @param ring - * the coordinates forming the ring - * @return the signed area of the ring - */ - public static double signedArea(Coordinate[] ring) - { - if (ring.length < 3) - return 0.0; - double sum = 0.0; - /** - * Based on the Shoelace formula. - * http://en.wikipedia.org/wiki/Shoelace_formula - */ - double x0 = ring[0].x; - for (int i = 1; i < ring.length - 1; i++) { - double x = ring[i].x - x0; - double y1 = ring[i + 1].y; - double y2 = ring[i - 1].y; - sum += x * (y2 - y1); - } - return sum / 2.0; - } - - /** - * Computes the signed area for a ring. The signed area is: - *
            - *
          • positive if the ring is oriented CW - *
          • negative if the ring is oriented CCW - *
          • zero if the ring is degenerate or flat - *
          - * - * @param ring - * the coordinates forming the ring - * @return the signed area of the ring - */ - public static double signedArea(CoordinateSequence ring) - { - int n = ring.size(); - if (n < 3) - return 0.0; - /** - * Based on the Shoelace formula. - * http://en.wikipedia.org/wiki/Shoelace_formula - */ - Coordinate p0 = new Coordinate(); - Coordinate p1 = new Coordinate(); - Coordinate p2 = new Coordinate(); - ring.getCoordinate(0, p1); - ring.getCoordinate(1, p2); - double x0 = p1.x; - p2.x -= x0; - double sum = 0.0; - for (int i = 1; i < n - 1; i++) { - p0.y = p1.y; - p1.x = p2.x; - p1.y = p2.y; - ring.getCoordinate(i + 1, p2); - p2.x -= x0; - sum += p1.x * (p0.y - p2.y); - } - return sum / 2.0; - } - - /** - * Computes the length of a linestring specified by a sequence of points. - * - * @param pts - * the points specifying the linestring - * @return the length of the linestring - */ - public static double length(CoordinateSequence pts) - { - // optimized for processing CoordinateSequences - int n = pts.size(); - if (n <= 1) - return 0.0; - - double len = 0.0; - - Coordinate p = new Coordinate(); - pts.getCoordinate(0, p); - double x0 = p.x; - double y0 = p.y; - - for (int i = 1; i < n; i++) { - pts.getCoordinate(i, p); - double x1 = p.x; - double y1 = p.y; - double dx = x1 - x0; - double dy = y1 - y0; - - len += Math.sqrt(dx * dx + dy * dy); - - x0 = x1; - y0 = y1; - } - return len; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms3D.java b/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms3D.java deleted file mode 100644 index 33cb22374f..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithms3D.java +++ /dev/null @@ -1,182 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.math.Vector3D; - -/** - * Basic computational geometry algorithms - * for geometry and coordinates defined in 3-dimensional Cartesian space. - * - * @author mdavis - * - */ -public class CGAlgorithms3D -{ - public static double distance(Coordinate p0, Coordinate p1) - { - // default to 2D distance if either Z is not set - if (Double.isNaN(p0.z) || Double.isNaN(p1.z)) - return p0.distance(p1); - - double dx = p0.x - p1.x; - double dy = p0.y - p1.y; - double dz = p0.z - p1.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - public static double distancePointSegment(Coordinate p, - Coordinate A, Coordinate B) { - // if start = end, then just compute distance to one of the endpoints - if (A.equals3D(B)) - return distance(p, A); - - // otherwise use comp.graphics.algorithms Frequently Asked Questions method - /* - * (1) r = AC dot AB - * --------- - * ||AB||^2 - * - * r has the following meaning: - * r=0 P = A - * r=1 P = B - * r<0 P is on the backward extension of AB - * r>1 P is on the forward extension of AB - * 0= 1.0) - return distance(p, B); - - // compute closest point q on line segment - double qx = A.x + r * (B.x - A.x); - double qy = A.y + r * (B.y - A.y); - double qz = A.z + r * (B.z - A.z); - // result is distance from p to q - double dx = p.x - qx; - double dy = p.y - qy; - double dz = p.z - qz; - return Math.sqrt(dx*dx + dy*dy + dz*dz); - } - - - /** - * Computes the distance between two 3D segments. - * - * @param A the start point of the first segment - * @param B the end point of the first segment - * @param C the start point of the second segment - * @param D the end point of the second segment - * @return the distance between the segments - */ - public static double distanceSegmentSegment( - Coordinate A, Coordinate B, Coordinate C, Coordinate D) - { - /** - * This calculation is susceptible to roundoff errors when - * passed large ordinate values. - * It may be possible to improve this by using {@link DD} arithmetic. - */ - if (A.equals3D(B)) - return distancePointSegment(A, C, D); - if (C.equals3D(B)) - return distancePointSegment(C, A, B); - - /** - * Algorithm derived from http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm - */ - double a = Vector3D.dot(A, B, A, B); - double b = Vector3D.dot(A, B, C, D); - double c = Vector3D.dot(C, D, C, D); - double d = Vector3D.dot(A, B, C, A); - double e = Vector3D.dot(C, D, C, A); - - double denom = a*c - b*b; - if (Double.isNaN(denom)) - throw new IllegalArgumentException("Ordinates must not be NaN"); - - double s; - double t; - if (denom <= 0.0) { - /** - * The lines are parallel. - * In this case solve for the parameters s and t by assuming s is 0. - */ - s = 0; - // choose largest denominator for optimal numeric conditioning - if (b > c) - t = d/b; - else - t = e/c; - } - else { - s = (b*e - c*d) / denom; - t = (a*e - b*d) / denom; - } - if (s < 0) - return distancePointSegment(A, C, D); - else if (s > 1) - return distancePointSegment(B, C, D); - else if (t < 0) - return distancePointSegment(C, A, B); - else if(t > 1) { - return distancePointSegment(D, A, B); - } - /** - * The closest points are in interiors of segments, - * so compute them directly - */ - double x1 = A.x + s * (B.x - A.x); - double y1 = A.y + s * (B.y - A.y); - double z1 = A.z + s * (B.z - A.z); - - double x2 = C.x + t * (D.x - C.x); - double y2 = C.y + t * (D.y - C.y); - double z2 = C.z + t * (D.z - C.z); - - // length (p1-p2) - return distance(new Coordinate(x1, y1, z1), new Coordinate(x2, y2, z2)); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithmsDD.java b/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithmsDD.java deleted file mode 100644 index 1e05fc86fd..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CGAlgorithmsDD.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.math.DD; - -/** - * Implements basic computational geometry algorithms using {@link DD} arithmetic. - * - * @author Martin Davis - * - */ -public class CGAlgorithmsDD -{ - /** - * Returns the index of the direction of the point q relative to - * a vector specified by p1-p2. - * - * @param p1 the origin point of the vector - * @param p2 the final point of the vector - * @param q the point to compute the direction to - * - * @return 1 if q is counter-clockwise (left) from p1-p2 - * @return -1 if q is clockwise (right) from p1-p2 - * @return 0 if q is collinear with p1-p2 - */ - public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) - { - // fast filter for orientation index - // avoids use of slow extended-precision arithmetic in many cases - int index = orientationIndexFilter(p1, p2, q); - if (index <= 1) return index; - - // normalize coordinates - DD dx1 = DD.valueOf(p2.x).selfAdd(-p1.x); - DD dy1 = DD.valueOf(p2.y).selfAdd(-p1.y); - DD dx2 = DD.valueOf(q.x).selfAdd(-p2.x); - DD dy2 = DD.valueOf(q.y).selfAdd(-p2.y); - - // sign of determinant - unrolled for performance - return dx1.selfMultiply(dy2).selfSubtract(dy1.selfMultiply(dx2)).signum(); - } - - /** - * Computes the sign of the determinant of the 2x2 matrix - * with the given entries. - * - * @return -1 if the determinant is negative, - * @return 1 if the determinant is positive, - * @return 0 if the determinant is 0. - */ - public static int signOfDet2x2(DD x1, DD y1, DD x2, DD y2) - { - DD det = x1.multiply(y2).selfSubtract(y1.multiply(x2)); - return det.signum(); - } - - /** - * A value which is safely greater than the - * relative round-off error in double-precision numbers - */ - private static final double DP_SAFE_EPSILON = 1e-15; - - /** - * A filter for computing the orientation index of three coordinates. - *

          - * If the orientation can be computed safely using standard DP - * arithmetic, this routine returns the orientation index. - * Otherwise, a value i > 1 is returned. - * In this case the orientation index must - * be computed using some other more robust method. - * The filter is fast to compute, so can be used to - * avoid the use of slower robust methods except when they are really needed, - * thus providing better average performance. - *

          - * Uses an approach due to Jonathan Shewchuk, which is in the public domain. - * - * @param pa a coordinate - * @param pb a coordinate - * @param pc a coordinate - * @return the orientation index if it can be computed safely - * @return i > 1 if the orientation index cannot be computed safely - */ - private static int orientationIndexFilter(Coordinate pa, Coordinate pb, Coordinate pc) - { - double detsum; - - double detleft = (pa.x - pc.x) * (pb.y - pc.y); - double detright = (pa.y - pc.y) * (pb.x - pc.x); - double det = detleft - detright; - - if (detleft > 0.0) { - if (detright <= 0.0) { - return signum(det); - } - else { - detsum = detleft + detright; - } - } - else if (detleft < 0.0) { - if (detright >= 0.0) { - return signum(det); - } - else { - detsum = -detleft - detright; - } - } - else { - return signum(det); - } - - double errbound = DP_SAFE_EPSILON * detsum; - if ((det >= errbound) || (-det >= errbound)) { - return signum(det); - } - - return 2; - } - - private static int signum(double x) - { - if (x > 0) return 1; - if (x < 0) return -1; - return 0; - } - - /** - * Computes an intersection point between two lines - * using DD arithmetic. - * Currently does not handle case of parallel lines. - * - * @param p1 - * @param p2 - * @param q1 - * @param q2 - * @return - */ - public static Coordinate intersection( - Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2) - { - DD denom1 = DD.valueOf(q2.y).selfSubtract(q1.y) - .selfMultiply(DD.valueOf(p2.x).selfSubtract(p1.x)); - DD denom2 = DD.valueOf(q2.x).selfSubtract(q1.x) - .selfMultiply(DD.valueOf(p2.y).selfSubtract(p1.y)); - DD denom = denom1.subtract(denom2); - - /** - * Cases: - * - denom is 0 if lines are parallel - * - intersection point lies within line segment p if fracP is between 0 and 1 - * - intersection point lies within line segment q if fracQ is between 0 and 1 - */ - - DD numx1 = DD.valueOf(q2.x).selfSubtract(q1.x) - .selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y)); - DD numx2 = DD.valueOf(q2.y).selfSubtract(q1.y) - .selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x)); - DD numx = numx1.subtract(numx2); - double fracP = numx.selfDivide(denom).doubleValue(); - - double x = DD.valueOf(p1.x).selfAdd(DD.valueOf(p2.x).selfSubtract(p1.x).selfMultiply(fracP)).doubleValue(); - - DD numy1 = DD.valueOf(p2.x).selfSubtract(p1.x) - .selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y)); - DD numy2 = DD.valueOf(p2.y).selfSubtract(p1.y) - .selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x)); - DD numy = numy1.subtract(numy2); - double fracQ = numy.selfDivide(denom).doubleValue(); - - double y = DD.valueOf(q1.y).selfAdd(DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(fracQ)).doubleValue(); - - return new Coordinate(x,y); - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CentralEndpointIntersector.java b/src/main/java/com/vividsolutions/jts/algorithm/CentralEndpointIntersector.java deleted file mode 100644 index 4d1f233460..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CentralEndpointIntersector.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; - - -/** - * Computes an approximate intersection of two line segments - * by taking the most central of the endpoints of the segments. - * This is effective in cases where the segments are nearly parallel - * and should intersect at an endpoint. - * It is also a reasonable strategy for cases where the - * endpoint of one segment lies on or almost on the interior of another one. - * Taking the most central endpoint ensures that the computed intersection - * point lies in the envelope of the segments. - * Also, by always returning one of the input points, this should result - * in reducing segment fragmentation. - * Intended to be used as a last resort for - * computing ill-conditioned intersection situations which - * cause other methods to fail. - *

          - * WARNING: in some cases this algorithm makes a poor choice of endpoint. - * It has been replaced by a better heuristic in {@link RobustLineIntersector}. - * - * @author Martin Davis - * @version 1.8 - * @deprecated - */ -public class CentralEndpointIntersector -{ - public static Coordinate getIntersection(Coordinate p00, Coordinate p01, - Coordinate p10, Coordinate p11) - { - CentralEndpointIntersector intor = new CentralEndpointIntersector(p00, p01, p10, p11); - return intor.getIntersection(); - } - - private Coordinate[] pts; - private Coordinate intPt = null; - - public CentralEndpointIntersector(Coordinate p00, Coordinate p01, - Coordinate p10, Coordinate p11) - { - pts = new Coordinate[] { p00, p01, p10, p11 }; - compute(); - } - - private void Ocompute() - { - Coordinate centroid = average(pts); - intPt = new Coordinate(findNearestPoint(centroid, pts)); - } - - public Coordinate getIntersection() { - return intPt; - } - - private static Coordinate average(Coordinate[] pts) - { - Coordinate avg = new Coordinate(); - int n = pts.length; - for (int i = 0; i < pts.length; i++) { - avg.x += pts[i].x; - avg.y += pts[i].y; - } - if (n > 0) { - avg.x /= n; - avg.y /= n; - } - return avg; - } - - /** - * Determines a point closest to the given point. - * - * @param p the point to compare against - * @param p1 a potential result point - * @param p2 a potential result point - * @param q1 a potential result point - * @param q2 a potential result point - * @return the point closest to the input point p - */ - private Coordinate findNearestPoint(Coordinate p, Coordinate[] pts) - { - double minDist = Double.MAX_VALUE; - Coordinate result = null; - for (int i = 0; i < pts.length; i++) { - double dist = p.distance(pts[i]); - // always initialize the result - if (i == 0 || dist < minDist) { - minDist = dist; - result = pts[i]; - } - } - return result; - } - - private double minDist = Double.MAX_VALUE; - - /** - * Finds point with smallest distance to other segment - */ - private void compute() - { - tryDist(pts[0], pts[2], pts[3]); - tryDist(pts[1], pts[2], pts[3]); - tryDist(pts[2], pts[0], pts[1]); - tryDist(pts[3], pts[0], pts[1]); - } - - private void tryDist(Coordinate p, Coordinate p0, Coordinate p1) - { - double dist = CGAlgorithms.distancePointLine(p, p0, p1); - if (dist < minDist) { - minDist = dist; - intPt = p; - } - } - - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/Centroid.java b/src/main/java/com/vividsolutions/jts/algorithm/Centroid.java deleted file mode 100644 index 2d02008672..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/Centroid.java +++ /dev/null @@ -1,273 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the centroid of a {@link Geometry} of any dimension. - * If the geometry is nominally of higher dimension, - * but has lower effective dimension - * (i.e. contains only components - * having zero length or area), - * the centroid will be computed as for the equivalent lower-dimension geometry. - * If the input geometry is empty, a - * null Coordinate is returned. - * - *

          Algorithm

          - *
            - *
          • Dimension 2 - the centroid is computed - * as the weighted sum of the centroids - * of a decomposition of the area into (possibly overlapping) triangles. - * Holes and multipolygons are handled correctly. - * See http://www.faqs.org/faqs/graphics/algorithms-faq/ - * for further details of the basic approach. - * - *
          • Dimension 1 - Computes the average of the midpoints - * of all line segments weighted by the segment length. - * Zero-length lines are treated as points. - * - *
          • Dimension 0 - Compute the average coordinate for all points. - * Repeated points are all included in the average. - *
          - * - * @version 1.7 - */ -public class Centroid -{ - /** - * Computes the centroid point of a geometry. - * - * @param geom the geometry to use - * @return the centroid point, or null if the geometry is empty - */ - public static Coordinate getCentroid(Geometry geom) - { - Centroid cent = new Centroid(geom); - return cent.getCentroid(); - } - - private Coordinate areaBasePt = null;// the point all triangles are based at - private Coordinate triangleCent3 = new Coordinate();// temporary variable to hold centroid of triangle - private double areasum2 = 0; /* Partial area sum */ - private Coordinate cg3 = new Coordinate(); // partial centroid sum - - // data for linear centroid computation, if needed - private Coordinate lineCentSum = new Coordinate(); - private double totalLength = 0.0; - - private int ptCount = 0; - private Coordinate ptCentSum = new Coordinate(); - - /** - * Creates a new instance for computing the centroid of a geometry - */ - public Centroid(Geometry geom) - { - areaBasePt = null; - add(geom); - } - - /** - * Adds a Geometry to the centroid total. - * - * @param geom the geometry to add - */ - private void add(Geometry geom) - { - if (geom.isEmpty()) - return; - if (geom instanceof Point) { - addPoint(geom.getCoordinate()); - } - else if (geom instanceof LineString) { - addLineSegments(geom.getCoordinates()); - } - else if (geom instanceof Polygon) { - Polygon poly = (Polygon) geom; - add(poly); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - - /** - * Gets the computed centroid. - * - * @return the computed centroid, or null if the input is empty - */ - public Coordinate getCentroid() - { - /** - * The centroid is computed from the highest dimension components present in the input. - * I.e. areas dominate lineal geometry, which dominates points. - * Degenerate geometry are computed using their effective dimension - * (e.g. areas may degenerate to lines or points) - */ - Coordinate cent = new Coordinate(); - if (Math.abs(areasum2) > 0.0) { - /** - * Input contains areal geometry - */ - cent.x = cg3.x / 3 / areasum2; - cent.y = cg3.y / 3 / areasum2; - } - else if (totalLength > 0.0) { - /** - * Input contains lineal geometry - */ - cent.x = lineCentSum.x / totalLength; - cent.y = lineCentSum.y / totalLength; - } - else if (ptCount > 0){ - /** - * Input contains puntal geometry only - */ - cent.x = ptCentSum.x / ptCount; - cent.y = ptCentSum.y / ptCount; - } - else { - return null; - } - return cent; - } - - private void setBasePoint(Coordinate basePt) - { - if (this.areaBasePt == null) - this.areaBasePt = basePt; - } - - private void add(Polygon poly) - { - addShell(poly.getExteriorRing().getCoordinates()); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - addHole(poly.getInteriorRingN(i).getCoordinates()); - } - } - - private void addShell(Coordinate[] pts) - { - if (pts.length > 0) - setBasePoint(pts[0]); - boolean isPositiveArea = ! CGAlgorithms.isCCW(pts); - for (int i = 0; i < pts.length - 1; i++) { - addTriangle(areaBasePt, pts[i], pts[i+1], isPositiveArea); - } - addLineSegments(pts); - } - - private void addHole(Coordinate[] pts) - { - boolean isPositiveArea = CGAlgorithms.isCCW(pts); - for (int i = 0; i < pts.length - 1; i++) { - addTriangle(areaBasePt, pts[i], pts[i+1], isPositiveArea); - } - addLineSegments(pts); - } - private void addTriangle(Coordinate p0, Coordinate p1, Coordinate p2, boolean isPositiveArea) - { - double sign = (isPositiveArea) ? 1.0 : -1.0; - centroid3( p0, p1, p2, triangleCent3 ); - double area2 = area2( p0, p1, p2 ); - cg3.x += sign * area2 * triangleCent3.x; - cg3.y += sign * area2 * triangleCent3.y; - areasum2 += sign * area2; - } - /** - * Computes three times the centroid of the triangle p1-p2-p3. - * The factor of 3 is - * left in to permit division to be avoided until later. - */ - private static void centroid3( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate c ) - { - c.x = p1.x + p2.x + p3.x; - c.y = p1.y + p2.y + p3.y; - return; - } - - /** - * Returns twice the signed area of the triangle p1-p2-p3. - * The area is positive if the triangle is oriented CCW, and negative if CW. - */ - private static double area2( Coordinate p1, Coordinate p2, Coordinate p3 ) - { - return - (p2.x - p1.x) * (p3.y - p1.y) - - (p3.x - p1.x) * (p2.y - p1.y); - } - - /** - * Adds the line segments defined by an array of coordinates - * to the linear centroid accumulators. - * - * @param pts an array of {@link Coordinate}s - */ - private void addLineSegments(Coordinate[] pts) - { - double lineLen = 0.0; - for (int i = 0; i < pts.length - 1; i++) { - double segmentLen = pts[i].distance(pts[i + 1]); - if (segmentLen == 0.0) - continue; - - lineLen += segmentLen; - - double midx = (pts[i].x + pts[i + 1].x) / 2; - lineCentSum.x += segmentLen * midx; - double midy = (pts[i].y + pts[i + 1].y) / 2; - lineCentSum.y += segmentLen * midy; - } - totalLength += lineLen; - if (lineLen == 0.0 && pts.length > 0) - addPoint(pts[0]); - } - - /** - * Adds a point to the point centroid accumulator. - * @param pt a {@link Coordinate} - */ - private void addPoint(Coordinate pt) - { - ptCount += 1; - ptCentSum.x += pt.x; - ptCentSum.y += pt.y; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CentroidArea.java b/src/main/java/com/vividsolutions/jts/algorithm/CentroidArea.java deleted file mode 100644 index b96efeb8e9..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CentroidArea.java +++ /dev/null @@ -1,202 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the centroid of an area geometry. - *

          Algorithm

          - * Based on the usual algorithm for calculating - * the centroid as a weighted sum of the centroids - * of a decomposition of the area into (possibly overlapping) triangles. - * The algorithm has been extended to handle holes and multi-polygons. - * See http://www.faqs.org/faqs/graphics/algorithms-faq/ - * for further details of the basic approach. - * The code has also be extended to handle degenerate (zero-area) polygons. - * In this case, the centroid of the line segments in the polygon - * will be returned. - * - * @version 1.7 - * @deprecated use Centroid instead - */ -public class CentroidArea -{ - private Coordinate basePt = null;// the point all triangles are based at - private Coordinate triangleCent3 = new Coordinate();// temporary variable to hold centroid of triangle - private double areasum2 = 0; /* Partial area sum */ - private Coordinate cg3 = new Coordinate(); // partial centroid sum - - // data for linear centroid computation, if needed - private Coordinate centSum = new Coordinate(); - private double totalLength = 0.0; - - public CentroidArea() - { - basePt = null; - } - - /** - * Adds the area defined by a Geometry to the centroid total. - * If the geometry has no area it does not contribute to the centroid. - * - * @param geom the geometry to add - */ - public void add(Geometry geom) - { - if (geom instanceof Polygon) { - Polygon poly = (Polygon) geom; - setBasePoint(poly.getExteriorRing().getCoordinateN(0)); - add(poly); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - - /** - * Adds the area defined by an array of - * coordinates. The array must be a ring; - * i.e. end with the same coordinate as it starts with. - * @param ring an array of {@link Coordinate}s - */ - public void add(Coordinate[] ring) - { - setBasePoint(ring[0]); - addShell(ring); - } - - public Coordinate getCentroid() - { - Coordinate cent = new Coordinate(); - if (Math.abs(areasum2) > 0.0) { - cent.x = cg3.x / 3 / areasum2; - cent.y = cg3.y / 3 / areasum2; - } - else { - // if polygon was degenerate, compute linear centroid instead - cent.x = centSum.x / totalLength; - cent.y = centSum.y / totalLength; - } - return cent; - } - - private void setBasePoint(Coordinate basePt) - { - if (this.basePt == null) - this.basePt = basePt; - } - - private void add(Polygon poly) - { - addShell(poly.getExteriorRing().getCoordinates()); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - addHole(poly.getInteriorRingN(i).getCoordinates()); - } - } - - private void addShell(Coordinate[] pts) - { - boolean isPositiveArea = ! CGAlgorithms.isCCW(pts); - for (int i = 0; i < pts.length - 1; i++) { - addTriangle(basePt, pts[i], pts[i+1], isPositiveArea); - } - addLinearSegments(pts); - } - private void addHole(Coordinate[] pts) - { - boolean isPositiveArea = CGAlgorithms.isCCW(pts); - for (int i = 0; i < pts.length - 1; i++) { - addTriangle(basePt, pts[i], pts[i+1], isPositiveArea); - } - addLinearSegments(pts); - } - private void addTriangle(Coordinate p0, Coordinate p1, Coordinate p2, boolean isPositiveArea) - { - double sign = (isPositiveArea) ? 1.0 : -1.0; - centroid3( p0, p1, p2, triangleCent3 ); - double area2 = area2( p0, p1, p2 ); - cg3.x += sign * area2 * triangleCent3.x; - cg3.y += sign * area2 * triangleCent3.y; - areasum2 += sign * area2; - } - /** - * Returns three times the centroid of the triangle p1-p2-p3. - * The factor of 3 is - * left in to permit division to be avoided until later. - */ - private static void centroid3( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate c ) - { - c.x = p1.x + p2.x + p3.x; - c.y = p1.y + p2.y + p3.y; - return; - } - - /** - * Returns twice the signed area of the triangle p1-p2-p3, - * positive if a,b,c are oriented ccw, and negative if cw. - */ - private static double area2( Coordinate p1, Coordinate p2, Coordinate p3 ) - { - return - (p2.x - p1.x) * (p3.y - p1.y) - - (p3.x - p1.x) * (p2.y - p1.y); - } - - /** - * Adds the linear segments defined by an array of coordinates - * to the linear centroid accumulators. - * This is done in case the polygon(s) have zero-area, - * in which case the linear centroid is computed instead. - * - * @param pts an array of {@link Coordinate}s - */ - private void addLinearSegments(Coordinate[] pts) - { - for (int i = 0; i < pts.length - 1; i++) { - double segmentLen = pts[i].distance(pts[i + 1]); - totalLength += segmentLen; - - double midx = (pts[i].x + pts[i + 1].x) / 2; - centSum.x += segmentLen * midx; - double midy = (pts[i].y + pts[i + 1].y) / 2; - centSum.y += segmentLen * midy; - } - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CentroidLine.java b/src/main/java/com/vividsolutions/jts/algorithm/CentroidLine.java deleted file mode 100644 index 7002e4689f..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CentroidLine.java +++ /dev/null @@ -1,108 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the centroid of a linear geometry. - *

          Algorithm

          - * Compute the average of the midpoints - * of all line segments weighted by the segment length. - * - * @version 1.7 - * @deprecated use Centroid instead - */ -public class CentroidLine -{ - private Coordinate centSum = new Coordinate(); - private double totalLength = 0.0; - - public CentroidLine() - { - } - - /** - * Adds the linear components of by a Geometry to the centroid total. - * If the geometry has no linear components it does not contribute to the centroid, - * - * @param geom the geometry to add - */ - public void add(Geometry geom) - { - if (geom instanceof LineString) { - add(geom.getCoordinates()); - } - else if (geom instanceof Polygon) { - Polygon poly = (Polygon) geom; - // add linear components of a polygon - add(poly.getExteriorRing().getCoordinates()); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - add(poly.getInteriorRingN(i).getCoordinates()); - } - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - - public Coordinate getCentroid() - { - Coordinate cent = new Coordinate(); - cent.x = centSum.x / totalLength; - cent.y = centSum.y / totalLength; - return cent; - } - - /** - * Adds the length defined by an array of coordinates. - * @param pts an array of {@link Coordinate}s - */ - public void add(Coordinate[] pts) - { - for (int i = 0; i < pts.length - 1; i++) { - double segmentLen = pts[i].distance(pts[i + 1]); - totalLength += segmentLen; - - double midx = (pts[i].x + pts[i + 1].x) / 2; - centSum.x += segmentLen * midx; - double midy = (pts[i].y + pts[i + 1].y) / 2; - centSum.y += segmentLen * midy; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/CentroidPoint.java b/src/main/java/com/vividsolutions/jts/algorithm/CentroidPoint.java deleted file mode 100644 index 44dfcc2bde..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/CentroidPoint.java +++ /dev/null @@ -1,92 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the centroid of a point geometry. - *

          Algorithm

          - * Compute the average of all points. - * - * @version 1.7 - * @deprecated use Centroid instead - */ -public class CentroidPoint -{ - private int ptCount = 0; - private Coordinate centSum = new Coordinate(); - - public CentroidPoint() - { - } - - /** - * Adds the point(s) defined by a Geometry to the centroid total. - * If the geometry is not of dimension 0 it does not contribute to the centroid. - * @param geom the geometry to add - */ - public void add(Geometry geom) - { - if (geom instanceof Point) { - add(geom.getCoordinate()); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - - /** - * Adds the length defined by an array of coordinates. - * @param pts an array of {@link Coordinate}s - */ - public void add(Coordinate pt) - { - ptCount += 1; - centSum.x += pt.x; - centSum.y += pt.y; - } - - public Coordinate getCentroid() - { - Coordinate cent = new Coordinate(); - cent.x = centSum.x / ptCount; - cent.y = centSum.y / ptCount; - return cent; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/ConvexHull.java b/src/main/java/com/vividsolutions/jts/algorithm/ConvexHull.java deleted file mode 100644 index d6427d6c6c..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/ConvexHull.java +++ /dev/null @@ -1,516 +0,0 @@ - - -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -import java.util.*; -import com.vividsolutions.jts.util.UniqueCoordinateArrayFilter; - -/** - * Computes the convex hull of a {@link Geometry}. - * The convex hull is the smallest convex Geometry that contains all the - * points in the input Geometry. - *

          - * Uses the Graham Scan algorithm. - * - *@version 1.7 - */ -public class ConvexHull -{ - private GeometryFactory geomFactory; - private Coordinate[] inputPts; - - /** - * Create a new convex hull construction for the input {@link Geometry}. - */ - public ConvexHull(Geometry geometry) - { - this(extractCoordinates(geometry), geometry.getFactory()); - } - /** - * Create a new convex hull construction for the input {@link Coordinate} array. - */ - public ConvexHull(Coordinate[] pts, GeometryFactory geomFactory) - { - inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts); - //inputPts = pts; - this.geomFactory = geomFactory; - } - - private static Coordinate[] extractCoordinates(Geometry geom) - { - UniqueCoordinateArrayFilter filter = new UniqueCoordinateArrayFilter(); - geom.apply(filter); - return filter.getCoordinates(); - } - - /** - * Returns a {@link Geometry} that represents the convex hull of the input - * geometry. - * The returned geometry contains the minimal number of points needed to - * represent the convex hull. In particular, no more than two consecutive - * points will be collinear. - * - * @return if the convex hull contains 3 or more points, a {@link Polygon}; - * 2 points, a {@link LineString}; - * 1 point, a {@link Point}; - * 0 points, an empty {@link GeometryCollection}. - */ - public Geometry getConvexHull() { - - if (inputPts.length == 0) { - return geomFactory.createGeometryCollection(null); - } - if (inputPts.length == 1) { - return geomFactory.createPoint(inputPts[0]); - } - if (inputPts.length == 2) { - return geomFactory.createLineString(inputPts); - } - - Coordinate[] reducedPts = inputPts; - // use heuristic to reduce points, if large - if (inputPts.length > 50) { - reducedPts = reduce(inputPts); - } - // sort points for Graham scan. - Coordinate[] sortedPts = preSort(reducedPts); - - // Use Graham scan to find convex hull. - Stack cHS = grahamScan(sortedPts); - - // Convert stack to an array. - Coordinate[] cH = toCoordinateArray(cHS); - - // Convert array to appropriate output geometry. - return lineOrPolygon(cH); - } - - /** - * An alternative to Stack.toArray, which is not present in earlier versions - * of Java. - */ - protected Coordinate[] toCoordinateArray(Stack stack) { - Coordinate[] coordinates = new Coordinate[stack.size()]; - for (int i = 0; i < stack.size(); i++) { - Coordinate coordinate = (Coordinate) stack.get(i); - coordinates[i] = coordinate; - } - return coordinates; - } - - /** - * Uses a heuristic to reduce the number of points scanned - * to compute the hull. - * The heuristic is to find a polygon guaranteed to - * be in (or on) the hull, and eliminate all points inside it. - * A quadrilateral defined by the extremal points - * in the four orthogonal directions - * can be used, but even more inclusive is - * to use an octilateral defined by the points in the 8 cardinal directions. - *

          - * Note that even if the method used to determine the polygon vertices - * is not 100% robust, this does not affect the robustness of the convex hull. - *

          - * To satisfy the requirements of the Graham Scan algorithm, - * the returned array has at least 3 entries. - * - * @param pts the points to reduce - * @return the reduced list of points (at least 3) - */ - private Coordinate[] reduce(Coordinate[] inputPts) - { - //Coordinate[] polyPts = computeQuad(inputPts); - Coordinate[] polyPts = computeOctRing(inputPts); - //Coordinate[] polyPts = null; - - // unable to compute interior polygon for some reason - if (polyPts == null) - return inputPts; - -// LinearRing ring = geomFactory.createLinearRing(polyPts); -// System.out.println(ring); - - // add points defining polygon - TreeSet reducedSet = new TreeSet(); - for (int i = 0; i < polyPts.length; i++) { - reducedSet.add(polyPts[i]); - } - /** - * Add all unique points not in the interior poly. - * CGAlgorithms.isPointInRing is not defined for points actually on the ring, - * but this doesn't matter since the points of the interior polygon - * are forced to be in the reduced set. - */ - for (int i = 0; i < inputPts.length; i++) { - if (! CGAlgorithms.isPointInRing(inputPts[i], polyPts)) { - reducedSet.add(inputPts[i]); - } - } - Coordinate[] reducedPts = CoordinateArrays.toCoordinateArray(reducedSet); - - // ensure that computed array has at least 3 points (not necessarily unique) - if (reducedPts.length < 3) - return padArray3(reducedPts); - return reducedPts; - } - - private Coordinate[] padArray3(Coordinate[] pts) - { - Coordinate[] pad = new Coordinate[3]; - for (int i = 0; i < pad.length; i++) { - if (i < pts.length) { - pad[i] = pts[i]; - } - else - pad[i] = pts[0]; - } - return pad; - } - - private Coordinate[] preSort(Coordinate[] pts) { - Coordinate t; - - // find the lowest point in the set. If two or more points have - // the same minimum y coordinate choose the one with the minimu x. - // This focal point is put in array location pts[0]. - for (int i = 1; i < pts.length; i++) { - if ((pts[i].y < pts[0].y) || ((pts[i].y == pts[0].y) && (pts[i].x < pts[0].x))) { - t = pts[0]; - pts[0] = pts[i]; - pts[i] = t; - } - } - - // sort the points radially around the focal point. - Arrays.sort(pts, 1, pts.length, new RadialComparator(pts[0])); - - //radialSort(pts); - return pts; - } - - /** - * Uses the Graham Scan algorithm to compute the convex hull vertices. - * - * @param c a list of points, with at least 3 entries - * @return a Stack containing the ordered points of the convex hull ring - */ - private Stack grahamScan(Coordinate[] c) { - Coordinate p; - Stack ps = new Stack(); - p = (Coordinate) ps.push(c[0]); - p = (Coordinate) ps.push(c[1]); - p = (Coordinate) ps.push(c[2]); - for (int i = 3; i < c.length; i++) { - p = (Coordinate) ps.pop(); - // check for empty stack to guard against robustness problems - while ( - ! ps.empty() && - CGAlgorithms.computeOrientation((Coordinate) ps.peek(), p, c[i]) > 0) { - p = (Coordinate) ps.pop(); - } - p = (Coordinate) ps.push(p); - p = (Coordinate) ps.push(c[i]); - } - p = (Coordinate) ps.push(c[0]); - return ps; - } - - /** - *@return whether the three coordinates are collinear and c2 lies between - * c1 and c3 inclusive - */ - private boolean isBetween(Coordinate c1, Coordinate c2, Coordinate c3) { - if (CGAlgorithms.computeOrientation(c1, c2, c3) != 0) { - return false; - } - if (c1.x != c3.x) { - if (c1.x <= c2.x && c2.x <= c3.x) { - return true; - } - if (c3.x <= c2.x && c2.x <= c1.x) { - return true; - } - } - if (c1.y != c3.y) { - if (c1.y <= c2.y && c2.y <= c3.y) { - return true; - } - if (c3.y <= c2.y && c2.y <= c1.y) { - return true; - } - } - return false; - } - - private Coordinate[] computeOctRing(Coordinate[] inputPts) { - Coordinate[] octPts = computeOctPts(inputPts); - CoordinateList coordList = new CoordinateList(); - coordList.add(octPts, false); - - // points must all lie in a line - if (coordList.size() < 3) { - return null; - } - coordList.closeRing(); - return coordList.toCoordinateArray(); - } - - private Coordinate[] computeOctPts(Coordinate[] inputPts) - { - Coordinate[] pts = new Coordinate[8]; - for (int j = 0; j < pts.length; j++) { - pts[j] = inputPts[0]; - } - for (int i = 1; i < inputPts.length; i++) { - if (inputPts[i].x < pts[0].x) { - pts[0] = inputPts[i]; - } - if (inputPts[i].x - inputPts[i].y < pts[1].x - pts[1].y) { - pts[1] = inputPts[i]; - } - if (inputPts[i].y > pts[2].y) { - pts[2] = inputPts[i]; - } - if (inputPts[i].x + inputPts[i].y > pts[3].x + pts[3].y) { - pts[3] = inputPts[i]; - } - if (inputPts[i].x > pts[4].x) { - pts[4] = inputPts[i]; - } - if (inputPts[i].x - inputPts[i].y > pts[5].x - pts[5].y) { - pts[5] = inputPts[i]; - } - if (inputPts[i].y < pts[6].y) { - pts[6] = inputPts[i]; - } - if (inputPts[i].x + inputPts[i].y < pts[7].x + pts[7].y) { - pts[7] = inputPts[i]; - } - } - return pts; - - } - -/* - // MD - no longer used, but keep for reference purposes - private Coordinate[] computeQuad(Coordinate[] inputPts) { - BigQuad bigQuad = bigQuad(inputPts); - - // Build a linear ring defining a big poly. - ArrayList bigPoly = new ArrayList(); - bigPoly.add(bigQuad.westmost); - if (! bigPoly.contains(bigQuad.northmost)) { - bigPoly.add(bigQuad.northmost); - } - if (! bigPoly.contains(bigQuad.eastmost)) { - bigPoly.add(bigQuad.eastmost); - } - if (! bigPoly.contains(bigQuad.southmost)) { - bigPoly.add(bigQuad.southmost); - } - // points must all lie in a line - if (bigPoly.size() < 3) { - return null; - } - // closing point - bigPoly.add(bigQuad.westmost); - - Coordinate[] bigPolyArray = CoordinateArrays.toCoordinateArray(bigPoly); - - return bigPolyArray; - } - - private BigQuad bigQuad(Coordinate[] pts) { - BigQuad bigQuad = new BigQuad(); - bigQuad.northmost = pts[0]; - bigQuad.southmost = pts[0]; - bigQuad.westmost = pts[0]; - bigQuad.eastmost = pts[0]; - for (int i = 1; i < pts.length; i++) { - if (pts[i].x < bigQuad.westmost.x) { - bigQuad.westmost = pts[i]; - } - if (pts[i].x > bigQuad.eastmost.x) { - bigQuad.eastmost = pts[i]; - } - if (pts[i].y < bigQuad.southmost.y) { - bigQuad.southmost = pts[i]; - } - if (pts[i].y > bigQuad.northmost.y) { - bigQuad.northmost = pts[i]; - } - } - return bigQuad; - } - - private static class BigQuad { - public Coordinate northmost; - public Coordinate southmost; - public Coordinate westmost; - public Coordinate eastmost; - } - */ - - /** - *@param vertices the vertices of a linear ring, which may or may not be - * flattened (i.e. vertices collinear) - *@return a 2-vertex LineString if the vertices are - * collinear; otherwise, a Polygon with unnecessary - * (collinear) vertices removed - */ - private Geometry lineOrPolygon(Coordinate[] coordinates) { - - coordinates = cleanRing(coordinates); - if (coordinates.length == 3) { - return geomFactory.createLineString(new Coordinate[]{coordinates[0], coordinates[1]}); -// return new LineString(new Coordinate[]{coordinates[0], coordinates[1]}, -// geometry.getPrecisionModel(), geometry.getSRID()); - } - LinearRing linearRing = geomFactory.createLinearRing(coordinates); - return geomFactory.createPolygon(linearRing, null); - } - - /** - *@param vertices the vertices of a linear ring, which may or may not be - * flattened (i.e. vertices collinear) - *@return the coordinates with unnecessary (collinear) vertices - * removed - */ - private Coordinate[] cleanRing(Coordinate[] original) { - Assert.equals(original[0], original[original.length - 1]); - ArrayList cleanedRing = new ArrayList(); - Coordinate previousDistinctCoordinate = null; - for (int i = 0; i <= original.length - 2; i++) { - Coordinate currentCoordinate = original[i]; - Coordinate nextCoordinate = original[i+1]; - if (currentCoordinate.equals(nextCoordinate)) { - continue; - } - if (previousDistinctCoordinate != null - && isBetween(previousDistinctCoordinate, currentCoordinate, nextCoordinate)) { - continue; - } - cleanedRing.add(currentCoordinate); - previousDistinctCoordinate = currentCoordinate; - } - cleanedRing.add(original[original.length - 1]); - Coordinate[] cleanedRingCoordinates = new Coordinate[cleanedRing.size()]; - return (Coordinate[]) cleanedRing.toArray(cleanedRingCoordinates); - } - - - /** - * Compares {@link Coordinate}s for their angle and distance - * relative to an origin. - * - * @author Martin Davis - * @version 1.7 - */ - private static class RadialComparator - implements Comparator - { - private Coordinate origin; - - public RadialComparator(Coordinate origin) - { - this.origin = origin; - } - public int compare(Object o1, Object o2) - { - Coordinate p1 = (Coordinate) o1; - Coordinate p2 = (Coordinate) o2; - return polarCompare(origin, p1, p2); - } - - /** - * Given two points p and q compare them with respect to their radial - * ordering about point o. First checks radial ordering. - * If points are collinear, the comparison is based - * on their distance to the origin. - *

          - * p < q iff - *

            - *
          • ang(o-p) < ang(o-q) (e.g. o-p-q is CCW) - *
          • or ang(o-p) == ang(o-q) && dist(o,p) < dist(o,q) - *
          - * - * @param o the origin - * @param p a point - * @param q another point - * @return -1, 0 or 1 depending on whether p is less than, - * equal to or greater than q - */ - private static int polarCompare(Coordinate o, Coordinate p, Coordinate q) - { - double dxp = p.x - o.x; - double dyp = p.y - o.y; - double dxq = q.x - o.x; - double dyq = q.y - o.y; - -/* - // MD - non-robust - int result = 0; - double alph = Math.atan2(dxp, dyp); - double beta = Math.atan2(dxq, dyq); - if (alph < beta) { - result = -1; - } - if (alph > beta) { - result = 1; - } - if (result != 0) return result; - //*/ - - int orient = CGAlgorithms.computeOrientation(o, p, q); - - if (orient == CGAlgorithms.COUNTERCLOCKWISE) return 1; - if (orient == CGAlgorithms.CLOCKWISE) return -1; - - // points are collinear - check distance - double op = dxp * dxp + dyp * dyp; - double oq = dxq * dxq + dyq * dyq; - if (op < oq) { - return -1; - } - if (op > oq) { - return 1; - } - return 0; - } - - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/algorithm/HCoordinate.java b/src/main/java/com/vividsolutions/jts/algorithm/HCoordinate.java deleted file mode 100644 index d6d2ae9471..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/HCoordinate.java +++ /dev/null @@ -1,188 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Represents a homogeneous coordinate in a 2-D coordinate space. - * In JTS {@link HCoordinate}s are used as a clean way - * of computing intersections between line segments. - * - * @author David Skea - * @version 1.7 - */ -public class HCoordinate -{ - - /** - * Computes the (approximate) intersection point between two line segments - * using homogeneous coordinates. - *

          - * Note that this algorithm is - * not numerically stable; i.e. it can produce intersection points which - * lie outside the envelope of the line segments themselves. In order - * to increase the precision of the calculation input points should be normalized - * before passing them to this routine. - */ - public static Coordinate intersection( - Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2) - throws NotRepresentableException - { - // unrolled computation - double px = p1.y - p2.y; - double py = p2.x - p1.x; - double pw = p1.x * p2.y - p2.x * p1.y; - - double qx = q1.y - q2.y; - double qy = q2.x - q1.x; - double qw = q1.x * q2.y - q2.x * q1.y; - - double x = py * qw - qy * pw; - double y = qx * pw - px * qw; - double w = px * qy - qx * py; - - double xInt = x/w; - double yInt = y/w; - - if ((Double.isNaN(xInt)) || (Double.isInfinite(xInt) - || Double.isNaN(yInt)) || (Double.isInfinite(yInt))) { - throw new NotRepresentableException(); - } - - return new Coordinate(xInt, yInt); - } - - /* - public static Coordinate OLDintersection( - Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2) - throws NotRepresentableException - { - HCoordinate l1 = new HCoordinate(p1, p2); - HCoordinate l2 = new HCoordinate(q1, q2); - HCoordinate intHCoord = new HCoordinate(l1, l2); - Coordinate intPt = intHCoord.getCoordinate(); - return intPt; - } - */ - - public double x,y,w; - - public HCoordinate() { - x = 0.0; - y = 0.0; - w = 1.0; - } - - public HCoordinate(double _x, double _y, double _w) { - x = _x; - y = _y; - w = _w; - } - - public HCoordinate(double _x, double _y) { - x = _x; - y = _y; - w = 1.0; - } - - public HCoordinate(Coordinate p) { - x = p.x; - y = p.y; - w = 1.0; - } - - public HCoordinate(HCoordinate p1, HCoordinate p2) - { - x = p1.y * p2.w - p2.y * p1.w; - y = p2.x * p1.w - p1.x * p2.w; - w = p1.x * p2.y - p2.x * p1.y; - } - - /** - * Constructs a homogeneous coordinate which is the intersection of the lines - * define by the homogenous coordinates represented by two - * {@link Coordinate}s. - * - * @param p1 - * @param p2 - */ - public HCoordinate(Coordinate p1, Coordinate p2) - { - // optimization when it is known that w = 1 - x = p1.y - p2.y; - y = p2.x - p1.x; - w = p1.x * p2.y - p2.x * p1.y; - } - - public HCoordinate(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) - { - // unrolled computation - double px = p1.y - p2.y; - double py = p2.x - p1.x; - double pw = p1.x * p2.y - p2.x * p1.y; - - double qx = q1.y - q2.y; - double qy = q2.x - q1.x; - double qw = q1.x * q2.y - q2.x * q1.y; - - x = py * qw - qy * pw; - y = qx * pw - px * qw; - w = px * qy - qx * py; - } - - public double getX() throws NotRepresentableException { - double a = x/w; - if ((Double.isNaN(a)) || (Double.isInfinite(a))) { - throw new NotRepresentableException(); - } - return a; - } - - public double getY() throws NotRepresentableException { - double a = y/w; - if ((Double.isNaN(a)) || (Double.isInfinite(a))) { - throw new NotRepresentableException(); - } - return a; - } - - public Coordinate getCoordinate() throws NotRepresentableException { - Coordinate p = new Coordinate(); - p.x = getX(); - p.y = getY(); - return p; - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointArea.java b/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointArea.java deleted file mode 100644 index 5cdd11ce2a..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointArea.java +++ /dev/null @@ -1,260 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes a point in the interior of an areal geometry. - * - *

          Algorithm

          - *
            - *
          • Find a Y value which is close to the centre of - * the geometry's vertical extent but is different - * to any of it's Y ordinates. - *
          • Create a horizontal bisector line using the Y value - * and the geometry's horizontal extent - *
          • Find the intersection between the geometry - * and the horizontal bisector line. - * The intersection is a collection of lines and points. - *
          • Pick the midpoint of the largest intersection geometry - *
          - * - *

          KNOWN BUGS

          - *
            - *
          • If a fixed precision model is used, - * in some cases this method may return a point - * which does not lie in the interior. - *
          - * - * @version 1.7 - */ -public class InteriorPointArea { - - private static double avg(double a, double b) - { - return (a + b) / 2.0; - } - - private GeometryFactory factory; - private Coordinate interiorPoint = null; - private double maxWidth = 0.0; - - /** - * Creates a new interior point finder - * for an areal geometry. - * - * @param g an areal geometry - */ - public InteriorPointArea(Geometry g) - { - factory = g.getFactory(); - add(g); - } - - /** - * Gets the computed interior point. - * - * @return the coordinate of an interior point - */ - public Coordinate getInteriorPoint() - { - return interiorPoint; - } - - /** - * Tests the interior vertices (if any) - * defined by an areal Geometry for the best inside point. - * If a component Geometry is not of dimension 2 it is not tested. - * - * @param geom the geometry to add - */ - private void add(Geometry geom) - { - if (geom instanceof Polygon) { - addPolygon(geom); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - - /** - * Finds an interior point of a Polygon. - * @param geometry the geometry to analyze - */ - private void addPolygon(Geometry geometry) { - if (geometry.isEmpty()) - return; - - Coordinate intPt; - double width = 0; - - LineString bisector = horizontalBisector(geometry); - if (bisector.getLength() == 0.0) { - width = 0; - intPt = bisector.getCoordinate(); - } - else { - Geometry intersections = bisector.intersection(geometry); - Geometry widestIntersection = widestGeometry(intersections); - width = widestIntersection.getEnvelopeInternal().getWidth(); - intPt = centre(widestIntersection.getEnvelopeInternal()); - } - if (interiorPoint == null || width > maxWidth) { - interiorPoint = intPt; - maxWidth = width; - } - } - - //@return if geometry is a collection, the widest sub-geometry; otherwise, - //the geometry itself - private Geometry widestGeometry(Geometry geometry) { - if (!(geometry instanceof GeometryCollection)) { - return geometry; - } - return widestGeometry((GeometryCollection) geometry); - } - - private Geometry widestGeometry(GeometryCollection gc) { - if (gc.isEmpty()) { - return gc; - } - - Geometry widestGeometry = gc.getGeometryN(0); - // scan remaining geom components to see if any are wider - for (int i = 1; i < gc.getNumGeometries(); i++) { - if (gc.getGeometryN(i).getEnvelopeInternal().getWidth() > - widestGeometry.getEnvelopeInternal().getWidth()) { - widestGeometry = gc.getGeometryN(i); - } - } - return widestGeometry; - } - - protected LineString horizontalBisector(Geometry geometry) { - Envelope envelope = geometry.getEnvelopeInternal(); - - /** - * Original algorithm. Fails when geometry contains a horizontal - * segment at the Y midpoint. - */ - // Assert: for areas, minx <> maxx - //double avgY = avg(envelope.getMinY(), envelope.getMaxY()); - - double bisectY = SafeBisectorFinder.getBisectorY((Polygon) geometry); - return factory.createLineString(new Coordinate[] { - new Coordinate(envelope.getMinX(), bisectY), - new Coordinate(envelope.getMaxX(), bisectY) - }); - } - - /** - * Returns the centre point of the envelope. - * @param envelope the envelope to analyze - * @return the centre of the envelope - */ - public static Coordinate centre(Envelope envelope) { - return new Coordinate(avg(envelope.getMinX(), - envelope.getMaxX()), - avg(envelope.getMinY(), envelope.getMaxY())); - } - - /** - * Finds a safe bisector Y ordinate - * by projecting to the Y axis - * and finding the Y-ordinate interval - * which contains the centre of the Y extent. - * The centre of this interval is returned as the bisector Y-ordinate. - * - * @author mdavis - * - */ - private static class SafeBisectorFinder - { - public static double getBisectorY(Polygon poly) - { - SafeBisectorFinder finder = new SafeBisectorFinder(poly); - return finder.getBisectorY(); - } - - private Polygon poly; - - private double centreY; - private double hiY = Double.MAX_VALUE; - private double loY = -Double.MAX_VALUE; - - public SafeBisectorFinder(Polygon poly) { - this.poly = poly; - - // initialize using extremal values - hiY = poly.getEnvelopeInternal().getMaxY(); - loY = poly.getEnvelopeInternal().getMinY(); - centreY = avg(loY, hiY); - } - - public double getBisectorY() - { - process(poly.getExteriorRing()); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - process(poly.getInteriorRingN(i)); - } - double bisectY = avg(hiY, loY); - return bisectY; - } - - private void process(LineString line) { - CoordinateSequence seq = line.getCoordinateSequence(); - for (int i = 0; i < seq.size(); i++) { - double y = seq.getY(i); - updateInterval(y); - } - } - - private void updateInterval(double y) { - if (y <= centreY) { - if (y > loY) - loY = y; - } - else if (y > centreY) { - if (y < hiY) { - hiY = y; - } - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointLine.java b/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointLine.java deleted file mode 100644 index 3b7d936ef2..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointLine.java +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes a point in the interior of an linear geometry. - *

          Algorithm

          - *
            - *
          • Find an interior vertex which is closest to - * the centroid of the linestring. - *
          • If there is no interior vertex, find the endpoint which is - * closest to the centroid. - *
          - * - * @version 1.7 - */ -public class InteriorPointLine { - - private Coordinate centroid; - private double minDistance = Double.MAX_VALUE; - - private Coordinate interiorPoint = null; - - public InteriorPointLine(Geometry g) - { - centroid = g.getCentroid().getCoordinate(); - addInterior(g); - if (interiorPoint == null) - addEndpoints(g); - } - - public Coordinate getInteriorPoint() - { - return interiorPoint; - } - - /** - * Tests the interior vertices (if any) - * defined by a linear Geometry for the best inside point. - * If a Geometry is not of dimension 1 it is not tested. - * @param geom the geometry to add - */ - private void addInterior(Geometry geom) - { - if (geom instanceof LineString) { - addInterior(geom.getCoordinates()); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - addInterior(gc.getGeometryN(i)); - } - } - } - private void addInterior(Coordinate[] pts) - { - for (int i = 1; i < pts.length - 1; i++) { - add(pts[i]); - } - } - /** - * Tests the endpoint vertices - * defined by a linear Geometry for the best inside point. - * If a Geometry is not of dimension 1 it is not tested. - * @param geom the geometry to add - */ - private void addEndpoints(Geometry geom) - { - if (geom instanceof LineString) { - addEndpoints(geom.getCoordinates()); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - addEndpoints(gc.getGeometryN(i)); - } - } - } - private void addEndpoints(Coordinate[] pts) - { - add(pts[0]); - add(pts[pts.length - 1]); - } - - private void add(Coordinate point) - { - double dist = point.distance(centroid); - if (dist < minDistance) { - interiorPoint = new Coordinate(point); - minDistance = dist; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointPoint.java b/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointPoint.java deleted file mode 100644 index ecb43582e9..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/InteriorPointPoint.java +++ /dev/null @@ -1,88 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes a point in the interior of an point geometry. - *

          Algorithm

          - * Find a point which is closest to the centroid of the geometry. - * - * @version 1.7 - */ -public class InteriorPointPoint { - - private Coordinate centroid; - private double minDistance = Double.MAX_VALUE; - - private Coordinate interiorPoint = null; - - public InteriorPointPoint(Geometry g) - { - centroid = g.getCentroid().getCoordinate(); - add(g); - } - - /** - * Tests the point(s) defined by a Geometry for the best inside point. - * If a Geometry is not of dimension 0 it is not tested. - * @param geom the geometry to add - */ - private void add(Geometry geom) - { - if (geom instanceof Point) { - add(geom.getCoordinate()); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - add(gc.getGeometryN(i)); - } - } - } - private void add(Coordinate point) - { - double dist = point.distance(centroid); - if (dist < minDistance) { - interiorPoint = new Coordinate(point); - minDistance = dist; - } - } - - public Coordinate getInteriorPoint() - { - return interiorPoint; - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/LineIntersector.java b/src/main/java/com/vividsolutions/jts/algorithm/LineIntersector.java deleted file mode 100644 index 0b6c1ebb5f..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/LineIntersector.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -/** - * @version 1.7 - */ -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * A LineIntersector is an algorithm that can both test whether - * two line segments intersect and compute the intersection point(s) - * if they do. - *

          - * There are three possible outcomes when determining whether two line segments intersect: - *

            - *
          • {@link #NO_INTERSECTION} - the segments do not intersect - *
          • {@link #POINT_INTERSECTION - the segments intersect in a single point - *
          • {@link #COLLINEAR_INTERSECTION - the segments are collinear and they intersect in a line segment - *
          - * For segments which intersect in a single point, the point may be either an endpoint - * or in the interior of each segment. - * If the point lies in the interior of both segments, - * this is termed a proper intersection. - * The method {@link #isProper()} test for this situation. - *

          - * The intersection point(s) may be computed in a precise or non-precise manner. - * Computing an intersection point precisely involves rounding it - * via a supplied {@link PrecisionModel}. - *

          - * LineIntersectors do not perform an initial envelope intersection test - * to determine if the segments are disjoint. - * This is because this class is likely to be used in a context where - * envelope overlap is already known to occur (or be likely). - * - * @version 1.7 - */ -public abstract class LineIntersector -{ -/** - * These are deprecated, due to ambiguous naming - */ - public final static int DONT_INTERSECT = 0; - public final static int DO_INTERSECT = 1; - public final static int COLLINEAR = 2; - - /** - * Indicates that line segments do not intersect - */ - public final static int NO_INTERSECTION = 0; - - /** - * Indicates that line segments intersect in a single point - */ - public final static int POINT_INTERSECTION = 1; - - /** - * Indicates that line segments intersect in a line segment - */ - public final static int COLLINEAR_INTERSECTION = 2; - - /** - * Computes the "edge distance" of an intersection point p along a segment. - * The edge distance is a metric of the point along the edge. - * The metric used is a robust and easy to compute metric function. - * It is not equivalent to the usual Euclidean metric. - * It relies on the fact that either the x or the y ordinates of the - * points in the edge are unique, depending on whether the edge is longer in - * the horizontal or vertical direction. - *

          - * NOTE: This function may produce incorrect distances - * for inputs where p is not precisely on p1-p2 - * (E.g. p = (139,9) p1 = (139,10), p2 = (280,1) produces distanct 0.0, which is incorrect. - *

          - * My hypothesis is that the function is safe to use for points which are the - * result of rounding points which lie on the line, - * but not safe to use for truncated points. - */ - public static double computeEdgeDistance( - Coordinate p, - Coordinate p0, - Coordinate p1) - { - double dx = Math.abs(p1.x - p0.x); - double dy = Math.abs(p1.y - p0.y); - - double dist = -1.0; // sentinel value - if (p.equals(p0)) { - dist = 0.0; - } - else if (p.equals(p1)) { - if (dx > dy) - dist = dx; - else - dist = dy; - } - else { - double pdx = Math.abs(p.x - p0.x); - double pdy = Math.abs(p.y - p0.y); - if (dx > dy) - dist = pdx; - else - dist = pdy; - // - // hack to ensure that non-endpoints always have a non-zero distance - if (dist == 0.0 && ! p.equals(p0)) - { - dist = Math.max(pdx, pdy); - } - } - Assert.isTrue(! (dist == 0.0 && ! p.equals(p0)), "Bad distance calculation"); - return dist; - } - - /** - * This function is non-robust, since it may compute the square of large numbers. - * Currently not sure how to improve this. - */ - public static double nonRobustComputeEdgeDistance( - Coordinate p, - Coordinate p1, - Coordinate p2) - { - double dx = p.x - p1.x; - double dy = p.y - p1.y; - double dist = Math.sqrt(dx * dx + dy * dy); // dummy value - Assert.isTrue(! (dist == 0.0 && ! p.equals(p1)), "Invalid distance calculation"); - return dist; - } - - protected int result; - protected Coordinate[][] inputLines = new Coordinate[2][2]; - protected Coordinate[] intPt = new Coordinate[2]; - /** - * The indexes of the endpoints of the intersection lines, in order along - * the corresponding line - */ - protected int[][] intLineIndex; - protected boolean isProper; - protected Coordinate pa; - protected Coordinate pb; - /** - * If makePrecise is true, computed intersection coordinates will be made precise - * using Coordinate#makePrecise - */ - protected PrecisionModel precisionModel = null; -//public int numIntersects = 0; - - public LineIntersector() { - intPt[0] = new Coordinate(); - intPt[1] = new Coordinate(); - // alias the intersection points for ease of reference - pa = intPt[0]; - pb = intPt[1]; - result = 0; - } - - /** - * Force computed intersection to be rounded to a given precision model - * @param precisionModel - * @deprecated use setPrecisionModel instead - */ - public void setMakePrecise(PrecisionModel precisionModel) - { - this.precisionModel = precisionModel; - } - - /** - * Force computed intersection to be rounded to a given precision model. - * No getter is provided, because the precision model is not required to be specified. - * @param precisionModel - */ - public void setPrecisionModel(PrecisionModel precisionModel) - { - this.precisionModel = precisionModel; - } - - /** - * Gets an endpoint of an input segment. - * - * @param segmentIndex the index of the input segment (0 or 1) - * @param ptIndex the index of the endpoint (0 or 1) - * @return the specified endpoint - */ - public Coordinate getEndpoint(int segmentIndex, int ptIndex) - { - return inputLines[segmentIndex][ptIndex]; - } - - /** - * Compute the intersection of a point p and the line p1-p2. - * This function computes the boolean value of the hasIntersection test. - * The actual value of the intersection (if there is one) - * is equal to the value of p. - */ - public abstract void computeIntersection( - Coordinate p, - Coordinate p1, Coordinate p2); - - protected boolean isCollinear() { - return result == COLLINEAR_INTERSECTION; - } - - /** - * Computes the intersection of the lines p1-p2 and p3-p4. - * This function computes both the boolean value of the hasIntersection test - * and the (approximate) value of the intersection point itself (if there is one). - */ - public void computeIntersection( - Coordinate p1, Coordinate p2, - Coordinate p3, Coordinate p4) { - inputLines[0][0] = p1; - inputLines[0][1] = p2; - inputLines[1][0] = p3; - inputLines[1][1] = p4; - result = computeIntersect(p1, p2, p3, p4); -//numIntersects++; - } - - protected abstract int computeIntersect( - Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2); - -/* - public String toString() { - String str = inputLines[0][0] + "-" - + inputLines[0][1] + " " - + inputLines[1][0] + "-" - + inputLines[1][1] + " : " - + getTopologySummary(); - return str; - } -*/ - - public String toString() { - return WKTWriter.toLineString(inputLines[0][0], inputLines[0][1]) + " - " - + WKTWriter.toLineString(inputLines[1][0], inputLines[1][1]) - + getTopologySummary(); - } - - private String getTopologySummary() - { - StringBuffer catBuf = new StringBuffer(); - if (isEndPoint()) catBuf.append(" endpoint"); - if (isProper) catBuf.append(" proper"); - if (isCollinear()) catBuf.append(" collinear"); - return catBuf.toString(); - } - - protected boolean isEndPoint() { - return hasIntersection() && !isProper; - } - - /** - * Tests whether the input geometries intersect. - * - * @return true if the input geometries intersect - */ - public boolean hasIntersection() { - return result != NO_INTERSECTION; - } - - /** - * Returns the number of intersection points found. This will be either 0, 1 or 2. - * - * @return the number of intersection points found (0, 1, or 2) - */ - public int getIntersectionNum() { return result; } - - /** - * Returns the intIndex'th intersection point - * - * @param intIndex is 0 or 1 - * - * @return the intIndex'th intersection point - */ - public Coordinate getIntersection(int intIndex) { return intPt[intIndex]; } - - protected void computeIntLineIndex() { - if (intLineIndex == null) { - intLineIndex = new int[2][2]; - computeIntLineIndex(0); - computeIntLineIndex(1); - } - } - - /** - * Test whether a point is a intersection point of two line segments. - * Note that if the intersection is a line segment, this method only tests for - * equality with the endpoints of the intersection segment. - * It does not return true if - * the input point is internal to the intersection segment. - * - * @return true if the input point is one of the intersection points. - */ - public boolean isIntersection(Coordinate pt) { - for (int i = 0; i < result; i++) { - if (intPt[i].equals2D(pt)) { - return true; - } - } - return false; - } - - /** - * Tests whether either intersection point is an interior point of one of the input segments. - * - * @return true if either intersection point is in the interior of one of the input segments - */ - public boolean isInteriorIntersection() - { - if (isInteriorIntersection(0)) return true; - if (isInteriorIntersection(1)) return true; - return false; - } - - /** - * Tests whether either intersection point is an interior point of the specified input segment. - * - * @return true if either intersection point is in the interior of the input segment - */ - public boolean isInteriorIntersection(int inputLineIndex) - { - for (int i = 0; i < result; i++) { - if (! ( intPt[i].equals2D(inputLines[inputLineIndex][0]) - || intPt[i].equals2D(inputLines[inputLineIndex][1]) )) { - return true; - } - } - return false; - } - - /** - * Tests whether an intersection is proper. - *
          - * The intersection between two line segments is considered proper if - * they intersect in a single point in the interior of both segments - * (e.g. the intersection is a single point and is not equal to any of the - * endpoints). - *

          - * The intersection between a point and a line segment is considered proper - * if the point lies in the interior of the segment (e.g. is not equal to - * either of the endpoints). - * - * @return true if the intersection is proper - */ - public boolean isProper() { - return hasIntersection() && isProper; - } - - /** - * Computes the intIndex'th intersection point in the direction of - * a specified input line segment - * - * @param segmentIndex is 0 or 1 - * @param intIndex is 0 or 1 - * - * @return the intIndex'th intersection point in the direction of the specified input line segment - */ - public Coordinate getIntersectionAlongSegment(int segmentIndex, int intIndex) { - // lazily compute int line array - computeIntLineIndex(); - return intPt[intLineIndex[segmentIndex][intIndex]]; - } - - /** - * Computes the index (order) of the intIndex'th intersection point in the direction of - * a specified input line segment - * - * @param segmentIndex is 0 or 1 - * @param intIndex is 0 or 1 - * - * @return the index of the intersection point along the input segment (0 or 1) - */ - public int getIndexAlongSegment(int segmentIndex, int intIndex) { - computeIntLineIndex(); - return intLineIndex[segmentIndex][intIndex]; - } - - protected void computeIntLineIndex(int segmentIndex) { - double dist0 = getEdgeDistance(segmentIndex, 0); - double dist1 = getEdgeDistance(segmentIndex, 1); - if (dist0 > dist1) { - intLineIndex[segmentIndex][0] = 0; - intLineIndex[segmentIndex][1] = 1; - } - else { - intLineIndex[segmentIndex][0] = 1; - intLineIndex[segmentIndex][1] = 0; - } - } - - /** - * Computes the "edge distance" of an intersection point along the specified input line segment. - * - * @param segmentIndex is 0 or 1 - * @param intIndex is 0 or 1 - * - * @return the edge distance of the intersection point - */ - public double getEdgeDistance(int segmentIndex, int intIndex) { - double dist = computeEdgeDistance(intPt[intIndex], inputLines[segmentIndex][0], - inputLines[segmentIndex][1]); - return dist; - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/MCPointInRing.java b/src/main/java/com/vividsolutions/jts/algorithm/MCPointInRing.java deleted file mode 100644 index a8e11d4dd5..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/MCPointInRing.java +++ /dev/null @@ -1,164 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import java.util.*; - -import com.vividsolutions.jts.algorithm.locate.IndexedPointInAreaLocator; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.index.chain.*; -import com.vividsolutions.jts.index.bintree.*; - -/** - * Implements {@link PointInRing} - * using {@link MonotoneChain}s and a {@link Bintree} index to - * increase performance. - * - * @version 1.7 - * - * @see IndexedPointInAreaLocator for more general functionality - */ -public class MCPointInRing implements PointInRing { - - class MCSelecter extends MonotoneChainSelectAction - { - Coordinate p; - - public MCSelecter(Coordinate p) - { - this.p = p; - } - - public void select(LineSegment ls) - { - testLineSegment(p, ls); - } - } - - private LinearRing ring; - private Bintree tree; - private int crossings = 0; // number of segment/ray crossings - - public MCPointInRing(LinearRing ring) - { - this.ring = ring; - buildIndex(); - } - - private void buildIndex() - { - //Envelope env = ring.getEnvelopeInternal(); - tree = new Bintree(); - - Coordinate[] pts = CoordinateArrays.removeRepeatedPoints(ring.getCoordinates()); - List mcList = MonotoneChainBuilder.getChains(pts); - - for (int i = 0; i < mcList.size(); i++) { - MonotoneChain mc = (MonotoneChain) mcList.get(i); - Envelope mcEnv = mc.getEnvelope(); - interval.min = mcEnv.getMinY(); - interval.max = mcEnv.getMaxY(); - tree.insert(interval, mc); - } - } - - private Interval interval = new Interval(); - - public boolean isInside(Coordinate pt) - { - crossings = 0; - - // test all segments intersected by ray from pt in positive x direction - Envelope rayEnv = new Envelope(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, pt.y, pt.y); - - interval.min = pt.y; - interval.max = pt.y; - List segs = tree.query(interval); -//System.out.println("query size = " + segs.size()); - - MCSelecter mcSelecter = new MCSelecter(pt); - for (Iterator i = segs.iterator(); i.hasNext(); ) { - MonotoneChain mc = (MonotoneChain) i.next(); - testMonotoneChain(rayEnv, mcSelecter, mc); - } - - /* - * p is inside if number of crossings is odd. - */ - if ((crossings % 2) == 1) { - return true; - } - return false; - } - - - private void testMonotoneChain(Envelope rayEnv, MCSelecter mcSelecter, MonotoneChain mc) - { - mc.select(rayEnv, mcSelecter); - } - - private void testLineSegment(Coordinate p, LineSegment seg) { - double xInt; // x intersection of segment with ray - double x1; // translated coordinates - double y1; - double x2; - double y2; - - /* - * Test if segment crosses ray from test point in positive x direction. - */ - Coordinate p1 = seg.p0; - Coordinate p2 = seg.p1; - x1 = p1.x - p.x; - y1 = p1.y - p.y; - x2 = p2.x - p.x; - y2 = p2.y - p.y; - - if (((y1 > 0) && (y2 <= 0)) || - ((y2 > 0) && (y1 <= 0))) { - /* - * segment straddles x axis, so compute intersection. - */ - xInt = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2) / (y2 - y1); - //xsave = xInt; - /* - * crosses ray if strictly positive intersection. - */ - if (0.0 < xInt) { - crossings++; - } - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/MinimumBoundingCircle.java b/src/main/java/com/vividsolutions/jts/algorithm/MinimumBoundingCircle.java deleted file mode 100644 index 6f099f8ad4..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/MinimumBoundingCircle.java +++ /dev/null @@ -1,362 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * Computes the Minimum Bounding Circle (MBC) - * for the points in a {@link Geometry}. - * The MBC is the smallest circle which covers - * all the input points - * (this is also known as the Smallest Enclosing Circle). - * This is equivalent to computing the Maximum Diameter - * of the input point set. - *

          - * The computed circle can be specified in two equivalent ways, - * both of which are provide as output by this class: - *

            - *
          • As a centre point and a radius - *
          • By the set of points defining the circle. - * Depending on the number of points in the input - * and their relative positions, this - * will be specified by anywhere from 0 to 3 points. - *
              - *
            • 0 or 1 points indicate an empty or trivial input point arrangement. - *
            • 2 or 3 points define a circle which contains - * all the input points. - *
            - *
          - * The class can also output a {@link Geometry} which approximates the - * shape of the MBC (although as an approximation - * it is not guaranteed to cover all the input points.) - * - * @author Martin Davis - * - * @see MinimumDiameter - * - */ -public class MinimumBoundingCircle -{ - /* - * The algorithm used is based on the one by Jon Rokne in - * the article "An Easy Bounding Circle" in Graphic Gems II. - */ - - private Geometry input; - private Coordinate[] extremalPts = null; - private Coordinate centre = null; - private double radius = 0.0; - - /** - * Creates a new object for computing the minimum bounding circle for the - * point set defined by the vertices of the given geometry. - * - * @param geom the geometry to use to obtain the point set - */ - public MinimumBoundingCircle(Geometry geom) - { - this.input = geom; - } - - /** - * Gets a geometry which represents the Minimum Bounding Circle. - * If the input is degenerate (empty or a single unique point), - * this method will return an empty geometry or a single Point geometry. - * Otherwise, a Polygon will be returned which approximates the - * Minimum Bounding Circle. - * (Note that because the computed polygon is only an approximation, - * it may not precisely contain all the input points.) - * - * @return a Geometry representing the Minimum Bounding Circle. - */ - public Geometry getCircle() - { - //TODO: ensure the output circle contains the extermal points. - //TODO: or maybe even ensure that the returned geometry contains ALL the input points? - - compute(); - if (centre == null) - return input.getFactory().createPolygon(null, null); - Point centrePoint = input.getFactory().createPoint(centre); - if (radius == 0.0) - return centrePoint; - return centrePoint.buffer(radius); - } - - /** - * Gets a geometry representing a line between the two farthest points - * in the input. - * These points will be two of the extremal points of the Minimum Bounding Circle. - * They also lie on the convex hull of the input. - * - * @return a LineString between the two farthest points of the input - * @return a empty LineString if the input is empty - * @return a Point if the input is a point - */ - public Geometry getFarthestPoints() { - compute(); - switch (extremalPts.length) { - case 0: - return input.getFactory().createLineString((CoordinateSequence) null); - case 1: - return input.getFactory().createPoint(centre); - } - Coordinate p0 = extremalPts[0]; - Coordinate p1 = extremalPts[extremalPts.length - 1]; - return input.getFactory().createLineString(new Coordinate[] { p0, p1 }); - } - - /** - * Gets a geometry representing the diameter of the computed Minimum Bounding - * Circle. - * - * @return the diameter LineString of the Minimum Bounding Circle - * @return a empty LineString if the input is empty - * @return a Point if the input is a point - */ - public Geometry getDiameter() { - compute(); - switch (extremalPts.length) { - case 0: - return input.getFactory().createLineString((CoordinateSequence) null); - case 1: - return input.getFactory().createPoint(centre); - } - // TODO: handle case of 3 extremal points, by computing a line from one of - // them through the centre point with len = 2*radius - Coordinate p0 = extremalPts[0]; - Coordinate p1 = extremalPts[1]; - return input.getFactory().createLineString(new Coordinate[] { p0, p1 }); - } - - /** - * Gets the extremal points which define the computed Minimum Bounding Circle. - * There may be zero, one, two or three of these points, - * depending on the number of points in the input - * and the geometry of those points. - * - * @return the points defining the Minimum Bounding Circle - */ - public Coordinate[] getExtremalPoints() - { - compute(); - return extremalPts; - } - - /** - * Gets the centre point of the computed Minimum Bounding Circle. - * - * @return the centre point of the Minimum Bounding Circle - * @return null if the input is empty - */ - public Coordinate getCentre() - { - compute(); - return centre; - } - - /** - * Gets the radius of the computed Minimum Bounding Circle. - * - * @return the radius of the Minimum Bounding Circle - */ - public double getRadius() - { - compute(); - return radius; - } - - private void computeCentre() - { - switch (extremalPts.length) { - case 0: - centre = null; - break; - case 1: - centre = extremalPts[0]; - break; - case 2: - centre = new Coordinate( - (extremalPts[0].x + extremalPts[1].x) / 2.0, - (extremalPts[0].y + extremalPts[1].y) / 2.0 - ); - break; - case 3: - centre = Triangle.circumcentre(extremalPts[0], extremalPts[1], extremalPts[2]); - break; - } - } - - private void compute() - { - if (extremalPts != null) return; - - computeCirclePoints(); - computeCentre(); - if (centre != null) - radius = centre.distance(extremalPts[0]); - } - - private void computeCirclePoints() - { - // handle degenerate or trivial cases - if (input.isEmpty()) { - extremalPts = new Coordinate[0]; - return; - } - if (input.getNumPoints() == 1) { - Coordinate[] pts = input.getCoordinates(); - extremalPts = new Coordinate[] { new Coordinate(pts[0]) }; - return; - } - - /** - * The problem is simplified by reducing to the convex hull. - * Computing the convex hull also has the useful effect of eliminating duplicate points - */ - Geometry convexHull = input.convexHull(); - - Coordinate[] hullPts = convexHull.getCoordinates(); - - // strip duplicate final point, if any - Coordinate[] pts = hullPts; - if (hullPts[0].equals2D(hullPts[hullPts.length - 1])) { - pts = new Coordinate[hullPts.length - 1]; - CoordinateArrays.copyDeep(hullPts, 0, pts, 0, hullPts.length - 1); - } - - /** - * Optimization for the trivial case where the CH has fewer than 3 points - */ - if (pts.length <= 2) { - extremalPts = CoordinateArrays.copyDeep(pts); - return; - } - - // find a point P with minimum Y ordinate - Coordinate P = lowestPoint(pts); - - // find a point Q such that the angle that PQ makes with the x-axis is minimal - Coordinate Q = pointWitMinAngleWithX(pts, P); - - /** - * Iterate over the remaining points to find - * a pair or triplet of points which determine the minimal circle. - * By the design of the algorithm, - * at most pts.length iterations are required to terminate - * with a correct result. - */ - for (int i = 0; i < pts.length; i++) { - Coordinate R = pointWithMinAngleWithSegment(pts, P, Q); - - // if PRQ is obtuse, then MBC is determined by P and Q - if (Angle.isObtuse(P, R, Q)) { - extremalPts = new Coordinate[] { new Coordinate(P), new Coordinate(Q) }; - return; - } - // if RPQ is obtuse, update baseline and iterate - if (Angle.isObtuse(R, P, Q)) { - P = R; - continue; - } - // if RQP is obtuse, update baseline and iterate - if (Angle.isObtuse(R, Q, P)) { - Q = R; - continue; - } - // otherwise all angles are acute, and the MBC is determined by the triangle PQR - extremalPts = new Coordinate[] { new Coordinate(P), new Coordinate(Q), new Coordinate(R) }; - return; - } - Assert.shouldNeverReachHere("Logic failure in Minimum Bounding Circle algorithm!"); - } - - private static Coordinate lowestPoint(Coordinate[] pts) - { - Coordinate min = pts[0]; - for (int i = 1; i < pts.length; i++) { - if (pts[i].y < min.y) - min = pts[i]; - } - return min; - } - - private static Coordinate pointWitMinAngleWithX(Coordinate[] pts, Coordinate P) - { - double minSin = Double.MAX_VALUE; - Coordinate minAngPt = null; - for (int i = 0; i < pts.length; i++) { - - Coordinate p = pts[i]; - if (p == P) continue; - - /** - * The sin of the angle is a simpler proxy for the angle itself - */ - double dx = p.x - P.x; - double dy = p.y - P.y; - if (dy < 0) dy = -dy; - double len = Math.sqrt(dx * dx + dy * dy); - double sin = dy / len; - - if (sin < minSin) { - minSin = sin; - minAngPt = p; - } - } - return minAngPt; - } - - private static Coordinate pointWithMinAngleWithSegment(Coordinate[] pts, Coordinate P, Coordinate Q) - { - double minAng = Double.MAX_VALUE; - Coordinate minAngPt = null; - for (int i = 0; i < pts.length; i++) { - - Coordinate p = pts[i]; - if (p == P) continue; - if (p == Q) continue; - - double ang = Angle.angleBetween(P, p, Q); - if (ang < minAng) { - minAng = ang; - minAngPt = p; - } - } - return minAngPt; - - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/MinimumDiameter.java b/src/main/java/com/vividsolutions/jts/algorithm/MinimumDiameter.java deleted file mode 100644 index e6a18ce993..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/MinimumDiameter.java +++ /dev/null @@ -1,358 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the minimum diameter of a {@link Geometry}. - * The minimum diameter is defined to be the - * width of the smallest band that - * contains the geometry, - * where a band is a strip of the plane defined - * by two parallel lines. - * This can be thought of as the smallest hole that the geometry can be - * moved through, with a single rotation. - *

          - * The first step in the algorithm is computing the convex hull of the Geometry. - * If the input Geometry is known to be convex, a hint can be supplied to - * avoid this computation. - *

          - * This class can also be used to compute a line segment representing - * the minimum diameter, the supporting line segment of the minimum diameter, - * and a minimum rectangle enclosing the input geometry. - * This rectangle will - * have width equal to the minimum diameter, and have one side - * parallel to the supporting segment. - * - * @see ConvexHull - * - * @version 1.7 - */ -public class MinimumDiameter -{ - /** - * Gets the minimum rectangle enclosing a geometry. - * - * @param geom the geometry - * @return the minimum rectangle enclosing the geometry - */ - public static Geometry getMinimumRectangle(Geometry geom) { - return (new MinimumDiameter(geom)).getMinimumRectangle(); - } - - /** - * Gets the length of the minimum diameter enclosing a geometry - * @param geom the geometry - * @return the length of the minimum diameter of the geometry - */ - public static Geometry getMinimumDiameter(Geometry geom) { - return (new MinimumDiameter(geom)).getDiameter(); - } - - private final Geometry inputGeom; - private final boolean isConvex; - - private Coordinate[] convexHullPts = null; - private LineSegment minBaseSeg = new LineSegment(); - private Coordinate minWidthPt = null; - private int minPtIndex; - private double minWidth = 0.0; - - /** - * Compute a minimum diameter for a given {@link Geometry}. - * - * @param geom a Geometry - */ - public MinimumDiameter(Geometry inputGeom) - { - this(inputGeom, false); - } - - /** - * Compute a minimum diameter for a giver {@link Geometry}, - * with a hint if - * the Geometry is convex - * (e.g. a convex Polygon or LinearRing, - * or a two-point LineString, or a Point). - * - * @param geom a Geometry which is convex - * @param isConvex true if the input geometry is convex - */ - public MinimumDiameter(Geometry inputGeom, boolean isConvex) - { - this.inputGeom = inputGeom; - this.isConvex = isConvex; - } - - /** - * Gets the length of the minimum diameter of the input Geometry - * - * @return the length of the minimum diameter - */ - public double getLength() - { - computeMinimumDiameter(); - return minWidth; - } - - /** - * Gets the {@link Coordinate} forming one end of the minimum diameter - * - * @return a coordinate forming one end of the minimum diameter - */ - public Coordinate getWidthCoordinate() - { - computeMinimumDiameter(); - return minWidthPt; - } - - /** - * Gets the segment forming the base of the minimum diameter - * - * @return the segment forming the base of the minimum diameter - */ - public LineString getSupportingSegment() - { - computeMinimumDiameter(); - return inputGeom.getFactory().createLineString(new Coordinate[] { minBaseSeg.p0, minBaseSeg.p1 } ); - } - - /** - * Gets a {@link LineString} which is a minimum diameter - * - * @return a {@link LineString} which is a minimum diameter - */ - public LineString getDiameter() - { - computeMinimumDiameter(); - - // return empty linestring if no minimum width calculated - if (minWidthPt == null) - return inputGeom.getFactory().createLineString((Coordinate[])null); - - Coordinate basePt = minBaseSeg.project(minWidthPt); - return inputGeom.getFactory().createLineString(new Coordinate[] { basePt, minWidthPt } ); - } - - private void computeMinimumDiameter() - { - // check if computation is cached - if (minWidthPt != null) - return; - - if (isConvex) - computeWidthConvex(inputGeom); - else { - Geometry convexGeom = (new ConvexHull(inputGeom)).getConvexHull(); - computeWidthConvex(convexGeom); - } - } - - private void computeWidthConvex(Geometry convexGeom) - { -//System.out.println("Input = " + geom); - if (convexGeom instanceof Polygon) - convexHullPts = ((Polygon) convexGeom).getExteriorRing().getCoordinates(); - else - convexHullPts = convexGeom.getCoordinates(); - - // special cases for lines or points or degenerate rings - if (convexHullPts.length == 0) { - minWidth = 0.0; - minWidthPt = null; - minBaseSeg = null; - } - else if (convexHullPts.length == 1) { - minWidth = 0.0; - minWidthPt = convexHullPts[0]; - minBaseSeg.p0 = convexHullPts[0]; - minBaseSeg.p1 = convexHullPts[0]; - } - else if (convexHullPts.length == 2 || convexHullPts.length == 3) { - minWidth = 0.0; - minWidthPt = convexHullPts[0]; - minBaseSeg.p0 = convexHullPts[0]; - minBaseSeg.p1 = convexHullPts[1]; - } - else - computeConvexRingMinDiameter(convexHullPts); - } - - /** - * Compute the width information for a ring of {@link Coordinate}s. - * Leaves the width information in the instance variables. - * - * @param pts - */ - private void computeConvexRingMinDiameter(Coordinate[] pts) - { - // for each segment in the ring - minWidth = Double.MAX_VALUE; - int currMaxIndex = 1; - - LineSegment seg = new LineSegment(); - // compute the max distance for all segments in the ring, and pick the minimum - for (int i = 0; i < pts.length - 1; i++) { - seg.p0 = pts[i]; - seg.p1 = pts[i + 1]; - currMaxIndex = findMaxPerpDistance(pts, seg, currMaxIndex); - } - } - - private int findMaxPerpDistance(Coordinate[] pts, LineSegment seg, int startIndex) - { - double maxPerpDistance = seg.distancePerpendicular(pts[startIndex]); - double nextPerpDistance = maxPerpDistance; - int maxIndex = startIndex; - int nextIndex = maxIndex; - while (nextPerpDistance >= maxPerpDistance) { - maxPerpDistance = nextPerpDistance; - maxIndex = nextIndex; - - nextIndex = nextIndex(pts, maxIndex); - nextPerpDistance = seg.distancePerpendicular(pts[nextIndex]); - } - // found maximum width for this segment - update global min dist if appropriate - if (maxPerpDistance < minWidth) { - minPtIndex = maxIndex; - minWidth = maxPerpDistance; - minWidthPt = pts[minPtIndex]; - minBaseSeg = new LineSegment(seg); -// System.out.println(minBaseSeg); -// System.out.println(minWidth); - } - return maxIndex; - } - - private static int nextIndex(Coordinate[] pts, int index) - { - index++; - if (index >= pts.length) index = 0; - return index; - } - - /** - * Gets the minimum rectangular {@link Polygon} which encloses the input geometry. - * The rectangle has width equal to the minimum diameter, - * and a longer length. - * If the convex hull of the input is degenerate (a line or point) - * a {@link LineString} or {@link Point} is returned. - *

          - * The minimum rectangle can be used as an extremely generalized representation - * for the given geometry. - * - * @return the minimum rectangle enclosing the input (or a line or point if degenerate) - */ - public Geometry getMinimumRectangle() - { - computeMinimumDiameter(); - - // check if minimum rectangle is degenerate (a point or line segment) - if (minWidth == 0.0) { - if (minBaseSeg.p0.equals2D(minBaseSeg.p1)) { - return inputGeom.getFactory().createPoint(minBaseSeg.p0); - } - return minBaseSeg.toGeometry(inputGeom.getFactory()); - } - - // deltas for the base segment of the minimum diameter - double dx = minBaseSeg.p1.x - minBaseSeg.p0.x; - double dy = minBaseSeg.p1.y - minBaseSeg.p0.y; - - /* - double c0 = computeC(dx, dy, minBaseSeg.p0); - double c1 = computeC(dx, dy, minBaseSeg.p1); - */ - - double minPara = Double.MAX_VALUE; - double maxPara = -Double.MAX_VALUE; - double minPerp = Double.MAX_VALUE; - double maxPerp = -Double.MAX_VALUE; - - // compute maxima and minima of lines parallel and perpendicular to base segment - for (int i = 0; i < convexHullPts.length; i++) { - - double paraC = computeC(dx, dy, convexHullPts[i]); - if (paraC > maxPara) maxPara = paraC; - if (paraC < minPara) minPara = paraC; - - double perpC = computeC(-dy, dx, convexHullPts[i]); - if (perpC > maxPerp) maxPerp = perpC; - if (perpC < minPerp) minPerp = perpC; - } - - // compute lines along edges of minimum rectangle - LineSegment maxPerpLine = computeSegmentForLine(-dx, -dy, maxPerp); - LineSegment minPerpLine = computeSegmentForLine(-dx, -dy, minPerp); - LineSegment maxParaLine = computeSegmentForLine(-dy, dx, maxPara); - LineSegment minParaLine = computeSegmentForLine(-dy, dx, minPara); - - // compute vertices of rectangle (where the para/perp max & min lines intersect) - Coordinate p0 = maxParaLine.lineIntersection(maxPerpLine); - Coordinate p1 = minParaLine.lineIntersection(maxPerpLine); - Coordinate p2 = minParaLine.lineIntersection(minPerpLine); - Coordinate p3 = maxParaLine.lineIntersection(minPerpLine); - - LinearRing shell = inputGeom.getFactory().createLinearRing( - new Coordinate[] { p0, p1, p2, p3, p0 }); - return inputGeom.getFactory().createPolygon(shell, null); - - } - - private static double computeC(double a, double b, Coordinate p) - { - return a * p.y - b * p.x; - } - - private static LineSegment computeSegmentForLine(double a, double b, double c) - { - Coordinate p0; - Coordinate p1; - /* - * Line eqn is ax + by = c - * Slope is a/b. - * If slope is steep, use y values as the inputs - */ - if (Math.abs(b) > Math.abs(a)) { - p0 = new Coordinate(0.0, c/b); - p1 = new Coordinate(1.0, c/b - a/b); - } - else { - p0 = new Coordinate(c/a, 0.0); - p1 = new Coordinate(c/a - b/a, 1.0); - } - return new LineSegment(p0, p1); - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java b/src/main/java/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java deleted file mode 100644 index 6c31f2eecf..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Non-robust versions of various fundamental Computational Geometric algorithms, - * FOR TESTING PURPOSES ONLY!. - * The non-robustness is due to rounding error in floating point computation. - * - * @version 1.7 - */ -public class NonRobustCGAlgorithms - extends CGAlgorithms -{ - public NonRobustCGAlgorithms() { - } - - /** - * Computes whether a ring defined by an array of {@link Coordinate} is - * oriented counter-clockwise. - *

          - * This will handle coordinate lists which contain repeated points. - * - * @param ring an array of coordinates forming a ring - * @return true if the ring is oriented counter-clockwise. - * @throws IllegalArgumentException if the ring is degenerate (does not contain 3 different points) - */ - public static boolean isPointInRing(Coordinate p, Coordinate[] ring) - { - int i, i1; // point index; i1 = i-1 mod n - double xInt; // x intersection of e with ray - int crossings = 0; // number of edge/ray crossings - double x1,y1,x2,y2; - int nPts = ring.length; - - /* For each line edge l = (i-1, i), see if it crosses ray from test point in positive x direction. */ - for (i = 1; i < nPts; i++ ) { - i1 = i - 1; - Coordinate p1 = ring[i]; - Coordinate p2 = ring[i1]; - x1 = p1.x - p.x; - y1 = p1.y - p.y; - x2 = p2.x - p.x; - y2 = p2.y - p.y; - - if( ( ( y1 > 0 ) && ( y2 <= 0 ) ) || - ( ( y2 > 0 ) && ( y1 <= 0 ) ) ) { - /* e straddles x axis, so compute intersection. */ - xInt = (x1 * y2 - x2 * y1) / (y2 - y1); - //xsave = xInt; - /* crosses ray if strictly positive intersection. */ - if (0.0 < xInt) - crossings++; - } - } - /* p is inside if an odd number of crossings. */ - if( (crossings % 2) == 1 ) - return true; - else - return false; - } - - /** - * Computes whether a ring defined by an array of {@link Coordinate} is - * oriented counter-clockwise. - *

          - * This will handle coordinate lists which contain repeated points. - * - * @param ring an array of coordinates forming a ring - * @return true if the ring is oriented counter-clockwise. - * @throws IllegalArgumentException if the ring is degenerate (does not contain 3 different points) - */ - public static boolean isCCW(Coordinate[] ring) - { - // # of points without closing endpoint - int nPts = ring.length - 1; - - // check that this is a valid ring - if not, simply return a dummy value - if (nPts < 4) return false; - - // algorithm to check if a Ring is stored in CCW order - // find highest point - Coordinate hip = ring[0]; - int hii = 0; - for (int i = 1; i <= nPts; i++) { - Coordinate p = ring[i]; - if (p.y > hip.y) { - hip = p; - hii = i; - } - } - - // find different point before highest point - int iPrev = hii; - do { - iPrev = (iPrev - 1) % nPts; - } while (ring[iPrev].equals(hip) && iPrev != hii); - - // find different point after highest point - int iNext = hii; - do { - iNext = (iNext + 1) % nPts; - } while (ring[iNext].equals(hip) && iNext != hii); - - Coordinate prev = ring[iPrev]; - Coordinate next = ring[iNext]; - - if (prev.equals(hip) || next.equals(hip) || prev.equals(next)) - throw new IllegalArgumentException("degenerate ring (does not contain 3 different points)"); - - // translate so that hip is at the origin. - // This will not affect the area calculation, and will avoid - // finite-accuracy errors (i.e very small vectors with very large coordinates) - // This also simplifies the discriminant calculation. - double prev2x = prev.x - hip.x; - double prev2y = prev.y - hip.y; - double next2x = next.x - hip.x; - double next2y = next.y - hip.y; - // compute cross-product of vectors hip->next and hip->prev - // (e.g. area of parallelogram they enclose) - double disc = next2x * prev2y - next2y * prev2x; - /* If disc is exactly 0, lines are collinear. There are two possible cases: - (1) the lines lie along the x axis in opposite directions - (2) the line lie on top of one another - (2) should never happen, so we're going to ignore it! - (Might want to assert this) - (1) is handled by checking if next is left of prev ==> CCW - */ - if (disc == 0.0) { - // poly is CCW if prev x is right of next x - return (prev.x > next.x); - } - else { - // if area is positive, points are ordered CCW - return (disc > 0.0); - } - } - - /** - * Computes the orientation of a point q to the directed line segment p1-p2. - * The orientation of a point relative to a directed line segment indicates - * which way you turn to get to q after travelling from p1 to p2. - * - * @return 1 if q is counter-clockwise from p1-p2 - * @return -1 if q is clockwise from p1-p2 - * @return 0 if q is collinear with p1-p2 - */ - public static int computeOrientation(Coordinate p1, Coordinate p2, Coordinate q) { - return orientationIndex(p1, p2, q); - } - - /** - * Returns the index of the direction of the point q relative to - * a vector specified by p1-p2. - * - * @param p1 - * the origin point of the vector - * @param p2 - * the final point of the vector - * @param q - * the point to compute the direction to - * - * @return 1 if q is counter-clockwise (left) from p1-p2 - * @return -1 if q is clockwise (right) from p1-p2 - * @return 0 if q is collinear with p1-p2 - */ - public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) - { - double dx1 = p2.x - p1.x; - double dy1 = p2.y - p1.y; - double dx2 = q.x - p2.x; - double dy2 = q.y - p2.y; - double det = dx1*dy2 - dx2*dy1; - if (det > 0.0) return 1; - if (det < 0.0) return -1; - return 0; - } - - /** - * Computes the distance from a line segment AB to a line segment CD - * - * Note: NON-ROBUST! - * - * @param A - * a point of one line - * @param B - * the second point of (must be different to A) - * @param C - * one point of the line - * @param D - * another point of the line (must be different to A) - */ - public static double distanceLineLine(Coordinate A, Coordinate B, - Coordinate C, Coordinate D) - { - // check for zero-length segments - if (A.equals(B)) - return distancePointLine(A, C, D); - if (C.equals(D)) - return distancePointLine(D, A, B); - - // AB and CD are line segments - /* - * from comp.graphics.algo - * - * Solving the above for r and s yields (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) r = - * ----------------------------- (eqn 1) (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - * - * (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------- (eqn 2) - * (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) Let P be the position vector of the - * intersection point, then P=A+r(B-A) or Px=Ax+r(Bx-Ax) Py=Ay+r(By-Ay) By - * examining the values of r & s, you can also determine some other limiting - * conditions: If 0<=r<=1 & 0<=s<=1, intersection exists r<0 or r>1 or s<0 - * or s>1 line segments do not intersect If the denominator in eqn 1 is - * zero, AB & CD are parallel If the numerator in eqn 1 is also zero, AB & - * CD are collinear. - */ - double r_top = (A.y - C.y) * (D.x - C.x) - (A.x - C.x) * (D.y - C.y); - double r_bot = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x); - - double s_top = (A.y - C.y) * (B.x - A.x) - (A.x - C.x) * (B.y - A.y); - double s_bot = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x); - - if ((r_bot == 0) || (s_bot == 0)) { - return Math - .min( - distancePointLine(A, C, D), - Math.min( - distancePointLine(B, C, D), - Math.min(distancePointLine(C, A, B), - distancePointLine(D, A, B)))); - - } - double s = s_top / s_bot; - double r = r_top / r_bot; - - if ((r < 0) || (r > 1) || (s < 0) || (s > 1)) { - // no intersection - return Math - .min( - distancePointLine(A, C, D), - Math.min( - distancePointLine(B, C, D), - Math.min(distancePointLine(C, A, B), - distancePointLine(D, A, B)))); - } - return 0.0; // intersection exists - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java b/src/main/java/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java deleted file mode 100644 index de5095b9da..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java +++ /dev/null @@ -1,320 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; -import com.vividsolutions.jts.algorithm.LineIntersector; - -/** - *@version 1.7 - */ - -import com.vividsolutions.jts.geom.*; -//import com.vividsolutions.jts.util.Debug; - -/** - * A non-robust version of {@link LineIntersector}. - * - * @version 1.7 - */ -public class NonRobustLineIntersector - extends LineIntersector -{ - /** - * @return true if both numbers are positive or if both numbers are negative. - * Returns false if both numbers are zero. - */ - public static boolean isSameSignAndNonZero(double a, double b) { - if (a == 0 || b == 0) { - return false; - } - return (a < 0 && b < 0) || (a > 0 && b > 0); - } - - - public NonRobustLineIntersector() { - } - - public void computeIntersection( - Coordinate p, - Coordinate p1, - Coordinate p2) { - double a1; - double b1; - double c1; - /* - * Coefficients of line eqns. - */ - double r; - /* - * 'Sign' values - */ - isProper = false; - - /* - * Compute a1, b1, c1, where line joining points 1 and 2 - * is "a1 x + b1 y + c1 = 0". - */ - a1 = p2.y - p1.y; - b1 = p1.x - p2.x; - c1 = p2.x * p1.y - p1.x * p2.y; - - /* - * Compute r3 and r4. - */ - r = a1 * p.x + b1 * p.y + c1; - - // if r != 0 the point does not lie on the line - if (r != 0) { - result = NO_INTERSECTION; - return; - } - - // Point lies on line - check to see whether it lies in line segment. - - double dist = rParameter(p1, p2, p); - if (dist < 0.0 || dist > 1.0) { - result = NO_INTERSECTION; - return; - } - - isProper = true; - if (p.equals(p1) || p.equals(p2)) { - isProper = false; - } - result = POINT_INTERSECTION; - } - - protected int computeIntersect( - Coordinate p1, - Coordinate p2, - Coordinate p3, - Coordinate p4) { - double a1; - double b1; - double c1; - /* - * Coefficients of line eqns. - */ - double a2; - /* - * Coefficients of line eqns. - */ - double b2; - /* - * Coefficients of line eqns. - */ - double c2; - double r1; - double r2; - double r3; - double r4; - /* - * 'Sign' values - */ - //double denom, offset, num; /* Intermediate values */ - - isProper = false; - - /* - * Compute a1, b1, c1, where line joining points 1 and 2 - * is "a1 x + b1 y + c1 = 0". - */ - a1 = p2.y - p1.y; - b1 = p1.x - p2.x; - c1 = p2.x * p1.y - p1.x * p2.y; - - /* - * Compute r3 and r4. - */ - r3 = a1 * p3.x + b1 * p3.y + c1; - r4 = a1 * p4.x + b1 * p4.y + c1; - - /* - * Check signs of r3 and r4. If both point 3 and point 4 lie on - * same side of line 1, the line segments do not intersect. - */ - if (r3 != 0 && - r4 != 0 && - isSameSignAndNonZero(r3, r4)) { - return NO_INTERSECTION; - } - - /* - * Compute a2, b2, c2 - */ - a2 = p4.y - p3.y; - b2 = p3.x - p4.x; - c2 = p4.x * p3.y - p3.x * p4.y; - - /* - * Compute r1 and r2 - */ - r1 = a2 * p1.x + b2 * p1.y + c2; - r2 = a2 * p2.x + b2 * p2.y + c2; - - /* - * Check signs of r1 and r2. If both point 1 and point 2 lie - * on same side of second line segment, the line segments do - * not intersect. - */ - if (r1 != 0 && - r2 != 0 && - isSameSignAndNonZero(r1, r2)) { - return NO_INTERSECTION; - } - - /** - * Line segments intersect: compute intersection point. - */ - double denom = a1 * b2 - a2 * b1; - if (denom == 0) { - return computeCollinearIntersection(p1, p2, p3, p4); - } - double numX = b1 * c2 - b2 * c1; - pa.x = numX / denom; - /* - * TESTING ONLY - * double valX = (( num < 0 ? num - offset : num + offset ) / denom); - * double valXInt = (int) (( num < 0 ? num - offset : num + offset ) / denom); - * if (valXInt != pa.x) // TESTING ONLY - * System.out.println(val + " - int: " + valInt + ", floor: " + pa.x); - */ - double numY = a2 * c1 - a1 * c2; - pa.y = numY / denom; - - // check if this is a proper intersection BEFORE truncating values, - // to avoid spurious equality comparisons with endpoints - isProper = true; - if (pa.equals(p1) || pa.equals(p2) || pa.equals(p3) || pa.equals(p4)) { - isProper = false; - } - - // truncate computed point to precision grid - // TESTING - don't force coord to be precise - if (precisionModel != null) { - precisionModel.makePrecise(pa); - } - return POINT_INTERSECTION; - } - - - /* - * p1-p2 and p3-p4 are assumed to be collinear (although - * not necessarily intersecting). Returns: - * DONT_INTERSECT : the two segments do not intersect - * COLLINEAR : the segments intersect, in the - * line segment pa-pb. pa-pb is in - * the same direction as p1-p2 - * DO_INTERSECT : the inputLines intersect in a single point - * only, pa - */ - private int computeCollinearIntersection( - Coordinate p1, - Coordinate p2, - Coordinate p3, - Coordinate p4) { - double r1; - double r2; - double r3; - double r4; - Coordinate q3; - Coordinate q4; - double t3; - double t4; - r1 = 0; - r2 = 1; - r3 = rParameter(p1, p2, p3); - r4 = rParameter(p1, p2, p4); - // make sure p3-p4 is in same direction as p1-p2 - if (r3 < r4) { - q3 = p3; - t3 = r3; - q4 = p4; - t4 = r4; - } - else { - q3 = p4; - t3 = r4; - q4 = p3; - t4 = r3; - } - // check for no intersection - if (t3 > r2 || t4 < r1) { - return NO_INTERSECTION; - } - - // check for single point intersection - if (q4 == p1) { - pa.setCoordinate(p1); - return POINT_INTERSECTION; - } - if (q3 == p2) { - pa.setCoordinate(p2); - return POINT_INTERSECTION; - } - - // intersection MUST be a segment - compute endpoints - pa.setCoordinate(p1); - if (t3 > r1) { - pa.setCoordinate(q3); - } - pb.setCoordinate(p2); - if (t4 < r2) { - pb.setCoordinate(q4); - } - return COLLINEAR_INTERSECTION; - } - - /** - * RParameter computes the parameter for the point p - * in the parameterized equation - * of the line from p1 to p2. - * This is equal to the 'distance' of p along p1-p2 - */ - private double rParameter(Coordinate p1, Coordinate p2, Coordinate p) { - double r; - // compute maximum delta, for numerical stability - // also handle case of p1-p2 being vertical or horizontal - double dx = Math.abs(p2.x - p1.x); - double dy = Math.abs(p2.y - p1.y); - if (dx > dy) { - r = (p.x - p1.x) / (p2.x - p1.x); - } - else { - r = (p.y - p1.y) / (p2.y - p1.y); - } - return r; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/NotRepresentableException.java b/src/main/java/com/vividsolutions/jts/algorithm/NotRepresentableException.java deleted file mode 100644 index 522f3496d9..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/NotRepresentableException.java +++ /dev/null @@ -1,51 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -/** - * Indicates that a {@link HCoordinate} has been computed which is - * not representable on the Cartesian plane. - * - * @version 1.7 - * @see HCoordinate - */ -public class NotRepresentableException extends Exception { - - public NotRepresentableException() { - super("Projective point not representable on the Cartesian plane."); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/PointInRing.java b/src/main/java/com/vividsolutions/jts/algorithm/PointInRing.java deleted file mode 100644 index d6e2104564..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/PointInRing.java +++ /dev/null @@ -1,49 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * An interface for classes which test whether a {@link Coordinate} lies inside - * a ring. - * - * @version 1.7 - * - * @see PointOnGeometryLocator - */ -public interface PointInRing { - - boolean isInside(Coordinate pt); -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/PointLocator.java b/src/main/java/com/vividsolutions/jts/algorithm/PointLocator.java deleted file mode 100644 index c9014cd422..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/PointLocator.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import java.util.Iterator; -import com.vividsolutions.jts.geom.*; - -/** - * Computes the topological ({@link Location}) - * of a single point to a {@link Geometry}. - * A {@link BoundaryNodeRule} may be specified - * to control the evaluation of whether the point lies on the boundary or not - * The default rule is to use the the SFS Boundary Determination Rule - *

          - * Notes: - *

            - *
          • {@link LinearRing}s do not enclose any area - points inside the ring are still in the EXTERIOR of the ring. - *
          - * Instances of this class are not reentrant. - * - * @version 1.7 - */ -public class PointLocator -{ - // default is to use OGC SFS rule - private BoundaryNodeRule boundaryRule = - //BoundaryNodeRule.ENDPOINT_BOUNDARY_RULE; - BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE; - - private boolean isIn; // true if the point lies in or on any Geometry element - private int numBoundaries; // the number of sub-elements whose boundaries the point lies in - - public PointLocator() { - } - - public PointLocator(BoundaryNodeRule boundaryRule) - { - if (boundaryRule == null) - throw new IllegalArgumentException("Rule must be non-null"); - this.boundaryRule = boundaryRule; - } - - /** - * Convenience method to test a point for intersection with - * a Geometry - * @param p the coordinate to test - * @param geom the Geometry to test - * @return true if the point is in the interior or boundary of the Geometry - */ - public boolean intersects(Coordinate p, Geometry geom) - { - return locate(p, geom) != Location.EXTERIOR; - } - - /** - * Computes the topological relationship ({@link Location}) of a single point - * to a Geometry. - * It handles both single-element - * and multi-element Geometries. - * The algorithm for multi-part Geometries - * takes into account the SFS Boundary Determination Rule. - * - * @return the {@link Location} of the point relative to the input Geometry - */ - public int locate(Coordinate p, Geometry geom) - { - if (geom.isEmpty()) return Location.EXTERIOR; - - if (geom instanceof LineString) { - return locate(p, (LineString) geom); - } - else if (geom instanceof Polygon) { - return locate(p, (Polygon) geom); - } - - isIn = false; - numBoundaries = 0; - computeLocation(p, geom); - if (boundaryRule.isInBoundary(numBoundaries)) - return Location.BOUNDARY; - if (numBoundaries > 0 || isIn) - return Location.INTERIOR; - - return Location.EXTERIOR; - } - - private void computeLocation(Coordinate p, Geometry geom) - { - if (geom instanceof Point) { - updateLocationInfo(locate(p, (Point) geom)); - } - if (geom instanceof LineString) { - updateLocationInfo(locate(p, (LineString) geom)); - } - else if (geom instanceof Polygon) { - updateLocationInfo(locate(p, (Polygon) geom)); - } - else if (geom instanceof MultiLineString) { - MultiLineString ml = (MultiLineString) geom; - for (int i = 0; i < ml.getNumGeometries(); i++) { - LineString l = (LineString) ml.getGeometryN(i); - updateLocationInfo(locate(p, l)); - } - } - else if (geom instanceof MultiPolygon) { - MultiPolygon mpoly = (MultiPolygon) geom; - for (int i = 0; i < mpoly.getNumGeometries(); i++) { - Polygon poly = (Polygon) mpoly.getGeometryN(i); - updateLocationInfo(locate(p, poly)); - } - } - else if (geom instanceof GeometryCollection) { - Iterator geomi = new GeometryCollectionIterator((GeometryCollection) geom); - while (geomi.hasNext()) { - Geometry g2 = (Geometry) geomi.next(); - if (g2 != geom) - computeLocation(p, g2); - } - } - } - - private void updateLocationInfo(int loc) - { - if (loc == Location.INTERIOR) isIn = true; - if (loc == Location.BOUNDARY) numBoundaries++; - } - - private int locate(Coordinate p, Point pt) - { - // no point in doing envelope test, since equality test is just as fast - - Coordinate ptCoord = pt.getCoordinate(); - if (ptCoord.equals2D(p)) - return Location.INTERIOR; - return Location.EXTERIOR; - } - - private int locate(Coordinate p, LineString l) - { - // bounding-box check - if (! l.getEnvelopeInternal().intersects(p)) return Location.EXTERIOR; - - Coordinate[] pt = l.getCoordinates(); - if (! l.isClosed()) { - if (p.equals(pt[0]) - || p.equals(pt[pt.length - 1]) ) { - return Location.BOUNDARY; - } - } - if (CGAlgorithms.isOnLine(p, pt)) - return Location.INTERIOR; - return Location.EXTERIOR; - } - - private int locateInPolygonRing(Coordinate p, LinearRing ring) - { - // bounding-box check - if (! ring.getEnvelopeInternal().intersects(p)) return Location.EXTERIOR; - - return CGAlgorithms.locatePointInRing(p, ring.getCoordinates()); - } - - private int locate(Coordinate p, Polygon poly) - { - if (poly.isEmpty()) return Location.EXTERIOR; - - LinearRing shell = (LinearRing) poly.getExteriorRing(); - - int shellLoc = locateInPolygonRing(p, shell); - if (shellLoc == Location.EXTERIOR) return Location.EXTERIOR; - if (shellLoc == Location.BOUNDARY) return Location.BOUNDARY; - // now test if the point lies in or on the holes - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - LinearRing hole = (LinearRing) poly.getInteriorRingN(i); - int holeLoc = locateInPolygonRing(p, hole); - if (holeLoc == Location.INTERIOR) return Location.EXTERIOR; - if (holeLoc == Location.BOUNDARY) return Location.BOUNDARY; - } - return Location.INTERIOR; - } - - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/RayCrossingCounter.java b/src/main/java/com/vividsolutions/jts/algorithm/RayCrossingCounter.java deleted file mode 100644 index 4ad30fc7c1..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/RayCrossingCounter.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Counts the number of segments crossed by a horizontal ray extending to the right - * from a given point, in an incremental fashion. - * This can be used to determine whether a point lies in a {@link Polygonal} geometry. - * The class determines the situation where the point lies exactly on a segment. - * When being used for Point-In-Polygon determination, this case allows short-circuiting - * the evaluation. - *

          - * This class handles polygonal geometries with any number of shells and holes. - * The orientation of the shell and hole rings is unimportant. - * In order to compute a correct location for a given polygonal geometry, - * it is essential that all segments are counted which - *

            - *
          • touch the ray - *
          • lie in in any ring which may contain the point - *
          - * The only exception is when the point-on-segment situation is detected, in which - * case no further processing is required. - * The implication of the above rule is that segments - * which can be a priori determined to not touch the ray - * (i.e. by a test of their bounding box or Y-extent) - * do not need to be counted. This allows for optimization by indexing. - * - * @author Martin Davis - * - */ -public class RayCrossingCounter -{ - /** - * Determines the {@link Location} of a point in a ring. - * This method is an exemplar of how to use this class. - * - * @param p the point to test - * @param ring an array of Coordinates forming a ring - * @return the location of the point in the ring - */ - public static int locatePointInRing(Coordinate p, Coordinate[] ring) - { - RayCrossingCounter counter = new RayCrossingCounter(p); - - for (int i = 1; i < ring.length; i++) { - Coordinate p1 = ring[i]; - Coordinate p2 = ring[i-1]; - counter.countSegment(p1, p2); - if (counter.isOnSegment()) - return counter.getLocation(); - } - return counter.getLocation(); - } - - /** - * Determines the {@link Location} of a point in a ring. - * - * @param p - * the point to test - * @param ring - * a coordinate sequence forming a ring - * @return the location of the point in the ring - */ - public static int locatePointInRing(Coordinate p, CoordinateSequence ring) { - RayCrossingCounter counter = new RayCrossingCounter(p); - - Coordinate p1 = new Coordinate(); - Coordinate p2 = new Coordinate(); - for (int i = 1; i < ring.size(); i++) { - ring.getCoordinate(i, p1); - ring.getCoordinate(i - 1, p2); - counter.countSegment(p1, p2); - if (counter.isOnSegment()) - return counter.getLocation(); - } - return counter.getLocation(); - } - - private Coordinate p; - private int crossingCount = 0; - // true if the test point lies on an input segment - private boolean isPointOnSegment = false; - - public RayCrossingCounter(Coordinate p) - { - this.p = p; - } - - /** - * Counts a segment - * - * @param p1 an endpoint of the segment - * @param p2 another endpoint of the segment - */ - public void countSegment(Coordinate p1, Coordinate p2) { - /** - * For each segment, check if it crosses - * a horizontal ray running from the test point in the positive x direction. - */ - - // check if the segment is strictly to the left of the test point - if (p1.x < p.x && p2.x < p.x) - return; - - // check if the point is equal to the current ring vertex - if (p.x == p2.x && p.y == p2.y) { - isPointOnSegment = true; - return; - } - /** - * For horizontal segments, check if the point is on the segment. - * Otherwise, horizontal segments are not counted. - */ - if (p1.y == p.y && p2.y == p.y) { - double minx = p1.x; - double maxx = p2.x; - if (minx > maxx) { - minx = p2.x; - maxx = p1.x; - } - if (p.x >= minx && p.x <= maxx) { - isPointOnSegment = true; - } - return; - } - /** - * Evaluate all non-horizontal segments which cross a horizontal ray to the - * right of the test pt. To avoid double-counting shared vertices, we use the - * convention that - *
            - *
          • an upward edge includes its starting endpoint, and excludes its - * final endpoint - *
          • a downward edge excludes its starting endpoint, and includes its - * final endpoint - *
          - */ - if (((p1.y > p.y) && (p2.y <= p.y)) - || ((p2.y > p.y) && (p1.y <= p.y))) { - // translate the segment so that the test point lies on the origin - double x1 = p1.x - p.x; - double y1 = p1.y - p.y; - double x2 = p2.x - p.x; - double y2 = p2.y - p.y; - - /** - * The translated segment straddles the x-axis. Compute the sign of the - * ordinate of intersection with the x-axis. (y2 != y1, so denominator - * will never be 0.0) - */ - // double xIntSign = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2) / (y2 - // - y1); - // MD - faster & more robust computation? - double xIntSign = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2); - if (xIntSign == 0.0) { - isPointOnSegment = true; - return; - } - if (y2 < y1) - xIntSign = -xIntSign; - // xsave = xInt; - - //System.out.println("xIntSign(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + " = " + xIntSign); - // The segment crosses the ray if the sign is strictly positive. - if (xIntSign > 0.0) { - crossingCount++; - } - } - } - -/** - * Reports whether the point lies exactly on one of the supplied segments. - * This method may be called at any time as segments are processed. - * If the result of this method is true, - * no further segments need be supplied, since the result - * will never change again. - * - * @return true if the point lies exactly on a segment - */ - public boolean isOnSegment() { return isPointOnSegment; } - - /** - * Gets the {@link Location} of the point relative to - * the ring, polygon - * or multipolygon from which the processed segments were provided. - *

          - * This method only determines the correct location - * if all relevant segments must have been processed. - * - * @return the Location of the point - */ - public int getLocation() - { - if (isPointOnSegment) - return Location.BOUNDARY; - - // The point is in the interior of the ring if the number of X-crossings is - // odd. - if ((crossingCount % 2) == 1) { - return Location.INTERIOR; - } - return Location.EXTERIOR; - } - - /** - * Tests whether the point lies in or on - * the ring, polygon - * or multipolygon from which the processed segments were provided. - *

          - * This method only determines the correct location - * if all relevant segments must have been processed. - * - * @return true if the point lies in or on the supplied polygon - */ - public boolean isPointInPolygon() - { - return getLocation() != Location.EXTERIOR; - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/RectangleLineIntersector.java b/src/main/java/com/vividsolutions/jts/algorithm/RectangleLineIntersector.java deleted file mode 100644 index baec3a332f..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/RectangleLineIntersector.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes whether a rectangle intersects line segments. - *

          - * Rectangles contain a large amount of inherent symmetry - * (or to put it another way, although they contain four - * coordinates they only actually contain 4 ordinates - * worth of information). - * The algorithm used takes advantage of the symmetry of - * the geometric situation - * to optimize performance by minimizing the number - * of line intersection tests. - * - * @author Martin Davis - * - */ -public class RectangleLineIntersector -{ - // for intersection testing, don't need to set precision model - private LineIntersector li = new RobustLineIntersector(); - - private Envelope rectEnv; - - private Coordinate diagUp0; - private Coordinate diagUp1; - private Coordinate diagDown0; - private Coordinate diagDown1; - - /** - * Creates a new intersector for the given query rectangle, - * specified as an {@link Envelope}. - * - * - * @param rectEnv the query rectangle, specified as an Envelope - */ - public RectangleLineIntersector(Envelope rectEnv) - { - this.rectEnv = rectEnv; - - /** - * Up and Down are the diagonal orientations - * relative to the Left side of the rectangle. - * Index 0 is the left side, 1 is the right side. - */ - diagUp0 = new Coordinate(rectEnv.getMinX(), rectEnv.getMinY()); - diagUp1 = new Coordinate(rectEnv.getMaxX(), rectEnv.getMaxY()); - diagDown0 = new Coordinate(rectEnv.getMinX(), rectEnv.getMaxY()); - diagDown1 = new Coordinate(rectEnv.getMaxX(), rectEnv.getMinY()); - } - - /** - * Tests whether the query rectangle intersects a - * given line segment. - * - * @param p0 the first endpoint of the segment - * @param p1 the second endpoint of the segment - * @return true if the rectangle intersects the segment - */ - public boolean intersects(Coordinate p0, Coordinate p1) - { - // TODO: confirm that checking envelopes first is faster - - /** - * If the segment envelope is disjoint from the - * rectangle envelope, there is no intersection - */ - Envelope segEnv = new Envelope(p0, p1); - if (! rectEnv.intersects(segEnv)) - return false; - - /** - * If either segment endpoint lies in the rectangle, - * there is an intersection. - */ - if (rectEnv.intersects(p0)) return true; - if (rectEnv.intersects(p1)) return true; - - /** - * Normalize segment. - * This makes p0 less than p1, - * so that the segment runs to the right, - * or vertically upwards. - */ - if (p0.compareTo(p1) > 0) { - Coordinate tmp = p0; - p0 = p1; - p1 = tmp; - } - /** - * Compute angle of segment. - * Since the segment is normalized to run left to right, - * it is sufficient to simply test the Y ordinate. - * "Upwards" means relative to the left end of the segment. - */ - boolean isSegUpwards = false; - if (p1.y > p0.y) - isSegUpwards = true; - - /** - * Since we now know that neither segment endpoint - * lies in the rectangle, there are two possible - * situations: - * 1) the segment is disjoint to the rectangle - * 2) the segment crosses the rectangle completely. - * - * In the case of a crossing, the segment must intersect - * a diagonal of the rectangle. - * - * To distinguish these two cases, it is sufficient - * to test intersection with - * a single diagonal of the rectangle, - * namely the one with slope "opposite" to the slope - * of the segment. - * (Note that if the segment is axis-parallel, - * it must intersect both diagonals, so this is - * still sufficient.) - */ - if (isSegUpwards) { - li.computeIntersection(p0, p1, diagDown0, diagDown1); - } - else { - li.computeIntersection(p0, p1, diagUp0, diagUp1); - } - if (li.hasIntersection()) - return true; - return false; - - - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java b/src/main/java/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java deleted file mode 100644 index 401b758ab0..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java +++ /dev/null @@ -1,47 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - - -/** - * Stub version of RobustCGAlgorithms for backwards compatibility. - * Will be deprecated in next release - use CGAlgorithms instead. - * - * @version 1.7 - * @deprecated use CGAlgorithms instead - */ -public class RobustCGAlgorithms extends CGAlgorithms { - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/RobustDeterminant.java b/src/main/java/com/vividsolutions/jts/algorithm/RobustDeterminant.java deleted file mode 100644 index d6967acd73..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/RobustDeterminant.java +++ /dev/null @@ -1,424 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * @version 1.7 - */ - -/** - * Implements an algorithm to compute the - * sign of a 2x2 determinant for double precision values robustly. - * It is a direct translation of code developed by Olivier Devillers. - *

          - * The original code carries the following copyright notice: - * - *

          - *************************************************************************
          - * Author : Olivier Devillers
          - * Olivier.Devillers@sophia.inria.fr
          - * http:/www.inria.fr:/prisme/personnel/devillers/anglais/determinant.html
          - * 
          - * Olivier Devillers has allowed the code to be distributed under
          - * the LGPL (2012-02-16) saying "It is ok for LGPL distribution."
          - * 
          - **************************************************************************
          - *
          - **************************************************************************
          - *              Copyright (c) 1995  by  INRIA Prisme Project
          - *                  BP 93 06902 Sophia Antipolis Cedex, France.
          - *                           All rights reserved
          - **************************************************************************
          - * 
          - * - * @version 1.7 - */ -public class RobustDeterminant { - - //public static int callCount = 0; // debugging only - - /* - // test point to allow injecting test code - public static int signOfDet2x2(double x1, double y1, double x2, double y2) - { - int d1 = originalSignOfDet2x2(x1, y1, x2, y2); - int d2 = -originalSignOfDet2x2(y1, x1, x2, y2); - assert d1 == -d2; - return d1; - } - */ - - /* - * Test code to force a standard ordering of input ordinates. - * A possible fix for a rare problem where evaluation is order-dependent. - */ - /* - public static int signOfDet2x2(double x1, double y1, double x2, double y2) - { - if (x1 > x2) { - return -signOfDet2x2ordX(x2, y2, x1, y1); - } - return signOfDet2x2ordX(x1, y1, x2, y2); - } - - private static int signOfDet2x2ordX(double x1, double y1, double x2, double y2) - { - if (y1 > y2) { - return -originalSignOfDet2x2(y1, x1, y2, x2); - } - return originalSignOfDet2x2(x1, y1, x2, y2); - } - // */ - - /** - * Computes the sign of the determinant of the 2x2 matrix - * with the given entries, in a robust way. - * - * @return -1 if the determinant is negative, - * @return 1 if the determinant is positive, - * @return 0 if the determinant is 0. - */ - //private static int originalSignOfDet2x2(double x1, double y1, double x2, double y2) { - public static int signOfDet2x2(double x1, double y1, double x2, double y2) { - // returns -1 if the determinant is negative, - // returns 1 if the determinant is positive, - // returns 0 if the determinant is null. - int sign; - double swap; - double k; - long count = 0; - - //callCount++; // debugging only - - sign = 1; - - /* - * testing null entries - */ - if ((x1 == 0.0) || (y2 == 0.0)) { - if ((y1 == 0.0) || (x2 == 0.0)) { - return 0; - } - else if (y1 > 0) { - if (x2 > 0) { - return -sign; - } - else { - return sign; - } - } - else { - if (x2 > 0) { - return sign; - } - else { - return -sign; - } - } - } - if ((y1 == 0.0) || (x2 == 0.0)) { - if (y2 > 0) { - if (x1 > 0) { - return sign; - } - else { - return -sign; - } - } - else { - if (x1 > 0) { - return -sign; - } - else { - return sign; - } - } - } - - /* - * making y coordinates positive and permuting the entries - */ - /* - * so that y2 is the biggest one - */ - if (0.0 < y1) { - if (0.0 < y2) { - if (y1 <= y2) { - ; - } - else { - sign = -sign; - swap = x1; - x1 = x2; - x2 = swap; - swap = y1; - y1 = y2; - y2 = swap; - } - } - else { - if (y1 <= -y2) { - sign = -sign; - x2 = -x2; - y2 = -y2; - } - else { - swap = x1; - x1 = -x2; - x2 = swap; - swap = y1; - y1 = -y2; - y2 = swap; - } - } - } - else { - if (0.0 < y2) { - if (-y1 <= y2) { - sign = -sign; - x1 = -x1; - y1 = -y1; - } - else { - swap = -x1; - x1 = x2; - x2 = swap; - swap = -y1; - y1 = y2; - y2 = swap; - } - } - else { - if (y1 >= y2) { - x1 = -x1; - y1 = -y1; - x2 = -x2; - y2 = -y2; - ; - } - else { - sign = -sign; - swap = -x1; - x1 = -x2; - x2 = swap; - swap = -y1; - y1 = -y2; - y2 = swap; - } - } - } - - /* - * making x coordinates positive - */ - /* - * if |x2| < |x1| one can conclude - */ - if (0.0 < x1) { - if (0.0 < x2) { - if (x1 <= x2) { - ; - } - else { - return sign; - } - } - else { - return sign; - } - } - else { - if (0.0 < x2) { - return -sign; - } - else { - if (x1 >= x2) { - sign = -sign; - x1 = -x1; - x2 = -x2; - ; - } - else { - return -sign; - } - } - } - - /* - * all entries strictly positive x1 <= x2 and y1 <= y2 - */ - while (true) { - count = count + 1; - // MD - UNSAFE HACK for testing only! -// k = (int) (x2 / x1); - k = Math.floor(x2 / x1); - x2 = x2 - k * x1; - y2 = y2 - k * y1; - - /* - * testing if R (new U2) is in U1 rectangle - */ - if (y2 < 0.0) { - return -sign; - } - if (y2 > y1) { - return sign; - } - - /* - * finding R' - */ - if (x1 > x2 + x2) { - if (y1 < y2 + y2) { - return sign; - } - } - else { - if (y1 > y2 + y2) { - return -sign; - } - else { - x2 = x1 - x2; - y2 = y1 - y2; - sign = -sign; - } - } - if (y2 == 0.0) { - if (x2 == 0.0) { - return 0; - } - else { - return -sign; - } - } - if (x2 == 0.0) { - return sign; - } - - /* - * exchange 1 and 2 role. - */ - // MD - UNSAFE HACK for testing only! -// k = (int) (x1 / x2); - k = Math.floor(x1 / x2); - x1 = x1 - k * x2; - y1 = y1 - k * y2; - - /* - * testing if R (new U1) is in U2 rectangle - */ - if (y1 < 0.0) { - return sign; - } - if (y1 > y2) { - return -sign; - } - - /* - * finding R' - */ - if (x2 > x1 + x1) { - if (y2 < y1 + y1) { - return -sign; - } - } - else { - if (y2 > y1 + y1) { - return sign; - } - else { - x1 = x2 - x1; - y1 = y2 - y1; - sign = -sign; - } - } - if (y1 == 0.0) { - if (x1 == 0.0) { - return 0; - } - else { - return sign; - } - } - if (x1 == 0.0) { - return -sign; - } - } - - } - - /** - * Returns the index of the direction of the point q relative to - * a vector specified by p1-p2. - * - * @param p1 the origin point of the vector - * @param p2 the final point of the vector - * @param q the point to compute the direction to - * - * @return 1 if q is counter-clockwise (left) from p1-p2 - * @return -1 if q is clockwise (right) from p1-p2 - * @return 0 if q is collinear with p1-p2 - */ - public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) - { - /** - * MD - 9 Aug 2010 It seems that the basic algorithm is slightly orientation - * dependent, when computing the orientation of a point very close to a - * line. This is possibly due to the arithmetic in the translation to the - * origin. - * - * For instance, the following situation produces identical results in spite - * of the inverse orientation of the line segment: - * - * Coordinate p0 = new Coordinate(219.3649559090992, 140.84159161824724); - * Coordinate p1 = new Coordinate(168.9018919682399, -5.713787599646864); - * - * Coordinate p = new Coordinate(186.80814046338352, 46.28973405831556); int - * orient = orientationIndex(p0, p1, p); int orientInv = - * orientationIndex(p1, p0, p); - * - * - */ - - double dx1 = p2.x - p1.x; - double dy1 = p2.y - p1.y; - double dx2 = q.x - p2.x; - double dy2 = q.y - p2.y; - return signOfDet2x2(dx1, dy1, dx2, dy2); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/RobustLineIntersector.java b/src/main/java/com/vividsolutions/jts/algorithm/RobustLineIntersector.java deleted file mode 100644 index 7b87f05a0e..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/RobustLineIntersector.java +++ /dev/null @@ -1,482 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -/** - *@version 1.7 - */ - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * A robust version of {@link LineIntersector}. - * - * @version 1.7 - * @see RobustDeterminant - */ -public class RobustLineIntersector - extends LineIntersector -{ - - public RobustLineIntersector() { - } - - public void computeIntersection(Coordinate p, Coordinate p1, Coordinate p2) { - isProper = false; - // do between check first, since it is faster than the orientation test - if (Envelope.intersects(p1, p2, p)) { - if ((CGAlgorithms.orientationIndex(p1, p2, p) == 0) - && (CGAlgorithms.orientationIndex(p2, p1, p) == 0)) { - isProper = true; - if (p.equals(p1) || p.equals(p2)) { - isProper = false; - } - result = POINT_INTERSECTION; - return; - } - } - result = NO_INTERSECTION; - } - - protected int computeIntersect( - Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2 ) { - isProper = false; - - // first try a fast test to see if the envelopes of the lines intersect - if (! Envelope.intersects(p1, p2, q1, q2)) - return NO_INTERSECTION; - - // for each endpoint, compute which side of the other segment it lies - // if both endpoints lie on the same side of the other segment, - // the segments do not intersect - int Pq1 = CGAlgorithms.orientationIndex(p1, p2, q1); - int Pq2 = CGAlgorithms.orientationIndex(p1, p2, q2); - - if ((Pq1>0 && Pq2>0) || (Pq1<0 && Pq2<0)) { - return NO_INTERSECTION; - } - - int Qp1 = CGAlgorithms.orientationIndex(q1, q2, p1); - int Qp2 = CGAlgorithms.orientationIndex(q1, q2, p2); - - if ((Qp1>0 && Qp2>0) || (Qp1<0 && Qp2<0)) { - return NO_INTERSECTION; - } - - boolean collinear = Pq1 == 0 - && Pq2 == 0 - && Qp1 == 0 - && Qp2 == 0; - if (collinear) { - return computeCollinearIntersection(p1, p2, q1, q2); - } - - /** - * At this point we know that there is a single intersection point - * (since the lines are not collinear). - */ - - /** - * Check if the intersection is an endpoint. If it is, copy the endpoint as - * the intersection point. Copying the point rather than computing it - * ensures the point has the exact value, which is important for - * robustness. It is sufficient to simply check for an endpoint which is on - * the other line, since at this point we know that the inputLines must - * intersect. - */ - if (Pq1 == 0 || Pq2 == 0 || Qp1 == 0 || Qp2 == 0) { - isProper = false; - - /** - * Check for two equal endpoints. - * This is done explicitly rather than by the orientation tests - * below in order to improve robustness. - * - * [An example where the orientation tests fail to be consistent is - * the following (where the true intersection is at the shared endpoint - * POINT (19.850257749638203 46.29709338043669) - * - * LINESTRING ( 19.850257749638203 46.29709338043669, 20.31970698357233 46.76654261437082 ) - * and - * LINESTRING ( -48.51001596420236 -22.063180333403878, 19.850257749638203 46.29709338043669 ) - * - * which used to produce the INCORRECT result: (20.31970698357233, 46.76654261437082, NaN) - * - */ - if (p1.equals2D(q1) - || p1.equals2D(q2)) { - intPt[0] = p1; - } - else if (p2.equals2D(q1) - || p2.equals2D(q2)) { - intPt[0] = p2; - } - - /** - * Now check to see if any endpoint lies on the interior of the other segment. - */ - else if (Pq1 == 0) { - intPt[0] = new Coordinate(q1); - } - else if (Pq2 == 0) { - intPt[0] = new Coordinate(q2); - } - else if (Qp1 == 0) { - intPt[0] = new Coordinate(p1); - } - else if (Qp2 == 0) { - intPt[0] = new Coordinate(p2); - } - } - else { - isProper = true; - intPt[0] = intersection(p1, p2, q1, q2); - } - return POINT_INTERSECTION; - } - - private int computeCollinearIntersection(Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2) { - boolean p1q1p2 = Envelope.intersects(p1, p2, q1); - boolean p1q2p2 = Envelope.intersects(p1, p2, q2); - boolean q1p1q2 = Envelope.intersects(q1, q2, p1); - boolean q1p2q2 = Envelope.intersects(q1, q2, p2); - - if (p1q1p2 && p1q2p2) { - intPt[0] = q1; - intPt[1] = q2; - return COLLINEAR_INTERSECTION; - } - if (q1p1q2 && q1p2q2) { - intPt[0] = p1; - intPt[1] = p2; - return COLLINEAR_INTERSECTION; - } - if (p1q1p2 && q1p1q2) { - intPt[0] = q1; - intPt[1] = p1; - return q1.equals(p1) && !p1q2p2 && !q1p2q2 ? POINT_INTERSECTION : COLLINEAR_INTERSECTION; - } - if (p1q1p2 && q1p2q2) { - intPt[0] = q1; - intPt[1] = p2; - return q1.equals(p2) && !p1q2p2 && !q1p1q2 ? POINT_INTERSECTION : COLLINEAR_INTERSECTION; - } - if (p1q2p2 && q1p1q2) { - intPt[0] = q2; - intPt[1] = p1; - return q2.equals(p1) && !p1q1p2 && !q1p2q2 ? POINT_INTERSECTION : COLLINEAR_INTERSECTION; - } - if (p1q2p2 && q1p2q2) { - intPt[0] = q2; - intPt[1] = p2; - return q2.equals(p2) && !p1q1p2 && !q1p1q2 ? POINT_INTERSECTION : COLLINEAR_INTERSECTION; - } - return NO_INTERSECTION; - } - - /** - * This method computes the actual value of the intersection point. - * To obtain the maximum precision from the intersection calculation, - * the coordinates are normalized by subtracting the minimum - * ordinate values (in absolute value). This has the effect of - * removing common significant digits from the calculation to - * maintain more bits of precision. - */ - private Coordinate intersection( - Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) - { - Coordinate intPt = intersectionWithNormalization(p1, p2, q1, q2); - - /* - // TESTING ONLY - Coordinate intPtDD = CGAlgorithmsDD.intersection(p1, p2, q1, q2); - double dist = intPt.distance(intPtDD); - System.out.println(intPt + " - " + intPtDD + " dist = " + dist); - //intPt = intPtDD; - */ - - /** - * Due to rounding it can happen that the computed intersection is - * outside the envelopes of the input segments. Clearly this - * is inconsistent. - * This code checks this condition and forces a more reasonable answer - * - * MD - May 4 2005 - This is still a problem. Here is a failure case: - * - * LINESTRING (2089426.5233462777 1180182.3877339689, 2085646.6891757075 1195618.7333999649) - * LINESTRING (1889281.8148903656 1997547.0560044837, 2259977.3672235999 483675.17050843034) - * int point = (2097408.2633752143,1144595.8008114607) - * - * MD - Dec 14 2006 - This does not seem to be a failure case any longer - */ - if (! isInSegmentEnvelopes(intPt)) { -// System.out.println("Intersection outside segment envelopes: " + intPt); - - // compute a safer result - // copy the coordinate, since it may be rounded later - intPt = new Coordinate(nearestEndpoint(p1, p2, q1, q2)); -// intPt = CentralEndpointIntersector.getIntersection(p1, p2, q1, q2); - -// System.out.println("Segments: " + this); -// System.out.println("Snapped to " + intPt); -// checkDD(p1, p2, q1, q2, intPt); - } - if (precisionModel != null) { - precisionModel.makePrecise(intPt); - } - return intPt; - } - - private void checkDD(Coordinate p1, Coordinate p2, Coordinate q1, - Coordinate q2, Coordinate intPt) - { - Coordinate intPtDD = CGAlgorithmsDD.intersection(p1, p2, q1, q2); - boolean isIn = isInSegmentEnvelopes(intPtDD); - System.out.println( "DD in env = " + isIn + " --------------------- " + intPtDD); - if (intPt.distance(intPtDD) > 0.0001) { - System.out.println("Distance = " + intPt.distance(intPtDD)); - } - } - - private Coordinate intersectionWithNormalization( - Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) - { - Coordinate n1 = new Coordinate(p1); - Coordinate n2 = new Coordinate(p2); - Coordinate n3 = new Coordinate(q1); - Coordinate n4 = new Coordinate(q2); - Coordinate normPt = new Coordinate(); - normalizeToEnvCentre(n1, n2, n3, n4, normPt); - - Coordinate intPt = safeHCoordinateIntersection(n1, n2, n3, n4); - - intPt.x += normPt.x; - intPt.y += normPt.y; - - return intPt; - } - - /** - * Computes a segment intersection using homogeneous coordinates. - * Round-off error can cause the raw computation to fail, - * (usually due to the segments being approximately parallel). - * If this happens, a reasonable approximation is computed instead. - * - * @param p1 a segment endpoint - * @param p2 a segment endpoint - * @param q1 a segment endpoint - * @param q2 a segment endpoint - * @return the computed intersection point - */ - private Coordinate safeHCoordinateIntersection(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) - { - Coordinate intPt = null; - try { - intPt = HCoordinate.intersection(p1, p2, q1, q2); - } - catch (NotRepresentableException e) { -// System.out.println("Not calculable: " + this); - // compute an approximate result -// intPt = CentralEndpointIntersector.getIntersection(p1, p2, q1, q2); - intPt = nearestEndpoint(p1, p2, q1, q2); - // System.out.println("Snapped to " + intPt); - } - return intPt; - } - - /** - * Normalize the supplied coordinates so that - * their minimum ordinate values lie at the origin. - * NOTE: this normalization technique appears to cause - * large errors in the position of the intersection point for some cases. - * - * @param n1 - * @param n2 - * @param n3 - * @param n4 - * @param normPt - */ - private void normalizeToMinimum( - Coordinate n1, - Coordinate n2, - Coordinate n3, - Coordinate n4, - Coordinate normPt) - { - normPt.x = smallestInAbsValue(n1.x, n2.x, n3.x, n4.x); - normPt.y = smallestInAbsValue(n1.y, n2.y, n3.y, n4.y); - n1.x -= normPt.x; n1.y -= normPt.y; - n2.x -= normPt.x; n2.y -= normPt.y; - n3.x -= normPt.x; n3.y -= normPt.y; - n4.x -= normPt.x; n4.y -= normPt.y; - } - - /** - * Normalize the supplied coordinates to - * so that the midpoint of their intersection envelope - * lies at the origin. - * - * @param n00 - * @param n01 - * @param n10 - * @param n11 - * @param normPt - */ - private void normalizeToEnvCentre( - Coordinate n00, - Coordinate n01, - Coordinate n10, - Coordinate n11, - Coordinate normPt) - { - double minX0 = n00.x < n01.x ? n00.x : n01.x; - double minY0 = n00.y < n01.y ? n00.y : n01.y; - double maxX0 = n00.x > n01.x ? n00.x : n01.x; - double maxY0 = n00.y > n01.y ? n00.y : n01.y; - - double minX1 = n10.x < n11.x ? n10.x : n11.x; - double minY1 = n10.y < n11.y ? n10.y : n11.y; - double maxX1 = n10.x > n11.x ? n10.x : n11.x; - double maxY1 = n10.y > n11.y ? n10.y : n11.y; - - double intMinX = minX0 > minX1 ? minX0 : minX1; - double intMaxX = maxX0 < maxX1 ? maxX0 : maxX1; - double intMinY = minY0 > minY1 ? minY0 : minY1; - double intMaxY = maxY0 < maxY1 ? maxY0 : maxY1; - - double intMidX = (intMinX + intMaxX) / 2.0; - double intMidY = (intMinY + intMaxY) / 2.0; - normPt.x = intMidX; - normPt.y = intMidY; - - /* - // equilavalent code using more modular but slower method - Envelope env0 = new Envelope(n00, n01); - Envelope env1 = new Envelope(n10, n11); - Envelope intEnv = env0.intersection(env1); - Coordinate intMidPt = intEnv.centre(); - - normPt.x = intMidPt.x; - normPt.y = intMidPt.y; - */ - - n00.x -= normPt.x; n00.y -= normPt.y; - n01.x -= normPt.x; n01.y -= normPt.y; - n10.x -= normPt.x; n10.y -= normPt.y; - n11.x -= normPt.x; n11.y -= normPt.y; - } - - private double smallestInAbsValue(double x1, double x2, double x3, double x4) - { - double x = x1; - double xabs = Math.abs(x); - if (Math.abs(x2) < xabs) { - x = x2; - xabs = Math.abs(x2); - } - if (Math.abs(x3) < xabs) { - x = x3; - xabs = Math.abs(x3); - } - if (Math.abs(x4) < xabs) { - x = x4; - } - return x; - } - - /** - * Tests whether a point lies in the envelopes of both input segments. - * A correctly computed intersection point should return true - * for this test. - * Since this test is for debugging purposes only, no attempt is - * made to optimize the envelope test. - * - * @return true if the input point lies within both input segment envelopes - */ - private boolean isInSegmentEnvelopes(Coordinate intPt) - { - Envelope env0 = new Envelope(inputLines[0][0], inputLines[0][1]); - Envelope env1 = new Envelope(inputLines[1][0], inputLines[1][1]); - return env0.contains(intPt) && env1.contains(intPt); - } - - /** - * Finds the endpoint of the segments P and Q which - * is closest to the other segment. - * This is a reasonable surrogate for the true - * intersection points in ill-conditioned cases - * (e.g. where two segments are nearly coincident, - * or where the endpoint of one segment lies almost on the other segment). - *

          - * This replaces the older CentralEndpoint heuristic, - * which chose the wrong endpoint in some cases - * where the segments had very distinct slopes - * and one endpoint lay almost on the other segment. - * - * @param p1 an endpoint of segment P - * @param p2 an endpoint of segment P - * @param q1 an endpoint of segment Q - * @param q2 an endpoint of segment Q - * @return the nearest endpoint to the other segment - */ - private static Coordinate nearestEndpoint(Coordinate p1, Coordinate p2, - Coordinate q1, Coordinate q2) - { - Coordinate nearestPt = p1; - double minDist = CGAlgorithms.distancePointLine(p1, q1, q2); - - double dist = CGAlgorithms.distancePointLine(p2, q1, q2); - if (dist < minDist) { - minDist = dist; - nearestPt = p2; - } - dist = CGAlgorithms.distancePointLine(q1, p1, p2); - if (dist < minDist) { - minDist = dist; - nearestPt = q1; - } - dist = CGAlgorithms.distancePointLine(q2, p1, p2); - if (dist < minDist) { - minDist = dist; - nearestPt = q2; - } - return nearestPt; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/SimplePointInRing.java b/src/main/java/com/vividsolutions/jts/algorithm/SimplePointInRing.java deleted file mode 100644 index 53701097d9..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/SimplePointInRing.java +++ /dev/null @@ -1,59 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm; - -import com.vividsolutions.jts.geom.*; - -/** - * Tests whether a {@link Coordinate} lies inside - * a ring, using a linear-time algorithm. - * - * @version 1.7 - */ -public class SimplePointInRing - implements PointInRing -{ - - private Coordinate[] pts; - - public SimplePointInRing(LinearRing ring) - { - pts = ring.getCoordinates(); - } - - public boolean isInside(Coordinate pt) - { - return CGAlgorithms.isPointInRing(pt, pts); - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/distance/DiscreteHausdorffDistance.java b/src/main/java/com/vividsolutions/jts/algorithm/distance/DiscreteHausdorffDistance.java deleted file mode 100644 index ac67894974..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/distance/DiscreteHausdorffDistance.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.algorithm.distance; - -import com.vividsolutions.jts.geom.*; - -/** - * An algorithm for computing a distance metric - * which is an approximation to the Hausdorff Distance - * based on a discretization of the input {@link Geometry}. - * The algorithm computes the Hausdorff distance restricted to discrete points - * for one of the geometries. - * The points can be either the vertices of the geometries (the default), - * or the geometries with line segments densified by a given fraction. - * Also determines two points of the Geometries which are separated by the computed distance. -*

          - * This algorithm is an approximation to the standard Hausdorff distance. - * Specifically, - *

          - *    for all geometries a, b:    DHD(a, b) <= HD(a, b)
          - * 
          - * The approximation can be made as close as needed by densifying the input geometries. - * In the limit, this value will approach the true Hausdorff distance: - *
          - *    DHD(A, B, densifyFactor) -> HD(A, B) as densifyFactor -> 0.0
          - * 
          - * The default approximation is exact or close enough for a large subset of useful cases. - * Examples of these are: - *
            - *
          • computing distance between Linestrings that are roughly parallel to each other, - * and roughly equal in length. This occurs in matching linear networks. - *
          • Testing similarity of geometries. - *
          - * An example where the default approximation is not close is: - *
          - *   A = LINESTRING (0 0, 100 0, 10 100, 10 100)
          - *   B = LINESTRING (0 100, 0 10, 80 10)
          - *   
          - *   DHD(A, B) = 22.360679774997898
          - *   HD(A, B) ~= 47.8
          - * 
          - */ -public class DiscreteHausdorffDistance -{ - public static double distance(Geometry g0, Geometry g1) - { - DiscreteHausdorffDistance dist = new DiscreteHausdorffDistance(g0, g1); - return dist.distance(); - } - - public static double distance(Geometry g0, Geometry g1, double densifyFrac) - { - DiscreteHausdorffDistance dist = new DiscreteHausdorffDistance(g0, g1); - dist.setDensifyFraction(densifyFrac); - return dist.distance(); - } - - private Geometry g0; - private Geometry g1; - private PointPairDistance ptDist = new PointPairDistance(); - - /** - * Value of 0.0 indicates that no densification should take place - */ - private double densifyFrac = 0.0; - - public DiscreteHausdorffDistance(Geometry g0, Geometry g1) - { - this.g0 = g0; - this.g1 = g1; - } - - /** - * Sets the fraction by which to densify each segment. - * Each segment will be (virtually) split into a number of equal-length - * subsegments, whose fraction of the total length is closest - * to the given fraction. - * - * @param densifyPercent - */ - public void setDensifyFraction(double densifyFrac) - { - if (densifyFrac > 1.0 - || densifyFrac <= 0.0) - throw new IllegalArgumentException("Fraction is not in range (0.0 - 1.0]"); - - this.densifyFrac = densifyFrac; - } - - public double distance() - { - compute(g0, g1); - return ptDist.getDistance(); - } - - public double orientedDistance() - { - computeOrientedDistance(g0, g1, ptDist); - return ptDist.getDistance(); - } - - public Coordinate[] getCoordinates() { return ptDist.getCoordinates(); } - - private void compute(Geometry g0, Geometry g1) - { - computeOrientedDistance(g0, g1, ptDist); - computeOrientedDistance(g1, g0, ptDist); - } - - private void computeOrientedDistance(Geometry discreteGeom, Geometry geom, PointPairDistance ptDist) - { - MaxPointDistanceFilter distFilter = new MaxPointDistanceFilter(geom); - discreteGeom.apply(distFilter); - ptDist.setMaximum(distFilter.getMaxPointDistance()); - - if (densifyFrac > 0) { - MaxDensifiedByFractionDistanceFilter fracFilter = new MaxDensifiedByFractionDistanceFilter(geom, densifyFrac); - discreteGeom.apply(fracFilter); - ptDist.setMaximum(fracFilter.getMaxPointDistance()); - - } - } - - public static class MaxPointDistanceFilter - implements CoordinateFilter - { - private PointPairDistance maxPtDist = new PointPairDistance(); - private PointPairDistance minPtDist = new PointPairDistance(); - private DistanceToPoint euclideanDist = new DistanceToPoint(); - private Geometry geom; - - public MaxPointDistanceFilter(Geometry geom) - { - this.geom = geom; - } - - public void filter(Coordinate pt) - { - minPtDist.initialize(); - DistanceToPoint.computeDistance(geom, pt, minPtDist); - maxPtDist.setMaximum(minPtDist); - } - - public PointPairDistance getMaxPointDistance() { return maxPtDist; } - } - - public static class MaxDensifiedByFractionDistanceFilter - implements CoordinateSequenceFilter - { - private PointPairDistance maxPtDist = new PointPairDistance(); - private PointPairDistance minPtDist = new PointPairDistance(); - private Geometry geom; - private int numSubSegs = 0; - - public MaxDensifiedByFractionDistanceFilter(Geometry geom, double fraction) { - this.geom = geom; - numSubSegs = (int) Math.rint(1.0/fraction); - } - - public void filter(CoordinateSequence seq, int index) - { - /** - * This logic also handles skipping Point geometries - */ - if (index == 0) - return; - - Coordinate p0 = seq.getCoordinate(index - 1); - Coordinate p1 = seq.getCoordinate(index); - - double delx = (p1.x - p0.x)/numSubSegs; - double dely = (p1.y - p0.y)/numSubSegs; - - for (int i = 0; i < numSubSegs; i++) { - double x = p0.x + i*delx; - double y = p0.y + i*dely; - Coordinate pt = new Coordinate(x, y); - minPtDist.initialize(); - DistanceToPoint.computeDistance(geom, pt, minPtDist); - maxPtDist.setMaximum(minPtDist); - } - - - } - - public boolean isGeometryChanged() { return false; } - - public boolean isDone() { return false; } - - public PointPairDistance getMaxPointDistance() { - return maxPtDist; - } -} - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/distance/DistanceToPoint.java b/src/main/java/com/vividsolutions/jts/algorithm/distance/DistanceToPoint.java deleted file mode 100644 index 336a8b240a..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/distance/DistanceToPoint.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm.distance; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the Euclidean distance (L2 metric) from a {@link Coordinate} to a {@link Geometry}. - * Also computes two points on the geometry which are separated by the distance found. - */ -public class DistanceToPoint -{ - - public DistanceToPoint() { - } - - public static void computeDistance(Geometry geom, Coordinate pt, PointPairDistance ptDist) - { - if (geom instanceof LineString) { - computeDistance((LineString) geom, pt, ptDist); - } - else if (geom instanceof Polygon) { - computeDistance((Polygon) geom, pt, ptDist); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - computeDistance(g, pt, ptDist); - } - } - else { // assume geom is Point - ptDist.setMinimum(geom.getCoordinate(), pt); - } - } - - public static void computeDistance(LineString line, Coordinate pt, PointPairDistance ptDist) - { - LineSegment tempSegment = new LineSegment(); - Coordinate[] coords = line.getCoordinates(); - for (int i = 0; i < coords.length - 1; i++) { - tempSegment.setCoordinates(coords[i], coords[i + 1]); - // this is somewhat inefficient - could do better - Coordinate closestPt = tempSegment.closestPoint(pt); - ptDist.setMinimum(closestPt, pt); - } - } - - public static void computeDistance(LineSegment segment, Coordinate pt, PointPairDistance ptDist) - { - Coordinate closestPt = segment.closestPoint(pt); - ptDist.setMinimum(closestPt, pt); - } - - public static void computeDistance(Polygon poly, Coordinate pt, PointPairDistance ptDist) - { - computeDistance(poly.getExteriorRing(), pt, ptDist); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - computeDistance(poly.getInteriorRingN(i), pt, ptDist); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/distance/PointPairDistance.java b/src/main/java/com/vividsolutions/jts/algorithm/distance/PointPairDistance.java deleted file mode 100644 index 8f6b365f61..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/distance/PointPairDistance.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.algorithm.distance; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * Contains a pair of points and the distance between them. - * Provides methods to update with a new point pair with - * either maximum or minimum distance. - */ -public class PointPairDistance { - - private Coordinate[] pt = { new Coordinate(), new Coordinate() }; - private double distance = Double.NaN; - private boolean isNull = true; - - public PointPairDistance() - { - } - - public void initialize() { isNull = true; } - - public void initialize(Coordinate p0, Coordinate p1) - { - pt[0].setCoordinate(p0); - pt[1].setCoordinate(p1); - distance = p0.distance(p1); - isNull = false; - } - - /** - * Initializes the points, avoiding recomputing the distance. - * @param p0 - * @param p1 - * @param distance the distance between p0 and p1 - */ - private void initialize(Coordinate p0, Coordinate p1, double distance) - { - pt[0].setCoordinate(p0); - pt[1].setCoordinate(p1); - this.distance = distance; - isNull = false; - } - - public double getDistance() { return distance; } - - public Coordinate[] getCoordinates() { return pt; } - - public Coordinate getCoordinate(int i) { return pt[i]; } - - public void setMaximum(PointPairDistance ptDist) - { - setMaximum(ptDist.pt[0], ptDist.pt[1]); - } - - public void setMaximum(Coordinate p0, Coordinate p1) - { - if (isNull) { - initialize(p0, p1); - return; - } - double dist = p0.distance(p1); - if (dist > distance) - initialize(p0, p1, dist); - } - - public void setMinimum(PointPairDistance ptDist) - { - setMinimum(ptDist.pt[0], ptDist.pt[1]); - } - - public void setMinimum(Coordinate p0, Coordinate p1) - { - if (isNull) { - initialize(p0, p1); - return; - } - double dist = p0.distance(p1); - if (dist < distance) - initialize(p0, p1, dist); - } - - public String toString() - { - return WKTWriter.toLineString(pt[0], pt[1]); - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/locate/IndexedPointInAreaLocator.java b/src/main/java/com/vividsolutions/jts/algorithm/locate/IndexedPointInAreaLocator.java deleted file mode 100644 index d093be42bb..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/locate/IndexedPointInAreaLocator.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm.locate; - -import java.util.*; - -import com.vividsolutions.jts.algorithm.RayCrossingCounter; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.index.*; -import com.vividsolutions.jts.index.intervalrtree.*; - -/** - * Determines the {@link Location} of {@link Coordinate}s relative to - * a {@link Polygonal} geometry, using indexing for efficiency. - * This algorithm is suitable for use in cases where - * many points will be tested against a given area. - * - * Thread-safe and immutable. - * - * @author Martin Davis - * - */ -public class IndexedPointInAreaLocator - implements PointOnGeometryLocator -{ - private final IntervalIndexedGeometry index; - - /** - * Creates a new locator for a given {@link Geometry} - * @param g the Geometry to locate in - */ - public IndexedPointInAreaLocator(Geometry g) - { - if (! (g instanceof Polygonal)) - throw new IllegalArgumentException("Argument must be Polygonal"); - index = new IntervalIndexedGeometry(g); - } - - /** - * Determines the {@link Location} of a point in an areal {@link Geometry}. - * - * @param p the point to test - * @return the location of the point in the geometry - */ - public int locate(Coordinate p) - { - RayCrossingCounter rcc = new RayCrossingCounter(p); - - SegmentVisitor visitor = new SegmentVisitor(rcc); - index.query(p.y, p.y, visitor); - - /* - // MD - slightly slower alternative - List segs = index.query(p.y, p.y); - countSegs(rcc, segs); - */ - - return rcc.getLocation(); - } - - private static class SegmentVisitor - implements ItemVisitor - { - private RayCrossingCounter counter; - - public SegmentVisitor(RayCrossingCounter counter) - { - this.counter = counter; - } - - public void visitItem(Object item) - { - LineSegment seg = (LineSegment) item; - counter.countSegment(seg.getCoordinate(0), seg.getCoordinate(1)); - } - } - - private static class IntervalIndexedGeometry - { - private final SortedPackedIntervalRTree index= new SortedPackedIntervalRTree(); - - public IntervalIndexedGeometry(Geometry geom) - { - init(geom); - } - - private void init(Geometry geom) - { - List lines = LinearComponentExtracter.getLines(geom); - for (Iterator i = lines.iterator(); i.hasNext(); ) { - LineString line = (LineString) i.next(); - Coordinate[] pts = line.getCoordinates(); - addLine(pts); - } - } - - private void addLine(Coordinate[] pts) - { - for (int i = 1; i < pts.length; i++) { - LineSegment seg = new LineSegment(pts[i-1], pts[i]); - double min = Math.min(seg.p0.y, seg.p1.y); - double max = Math.max(seg.p0.y, seg.p1.y); - index.insert(min, max, seg); - } - } - - public List query(double min, double max) - { - ArrayListVisitor visitor = new ArrayListVisitor(); - index.query(min, max, visitor); - return visitor.getItems(); - } - - public void query(double min, double max, ItemVisitor visitor) - { - index.query(min, max, visitor); - } - } - -} - - - diff --git a/src/main/java/com/vividsolutions/jts/algorithm/locate/PointOnGeometryLocator.java b/src/main/java/com/vividsolutions/jts/algorithm/locate/PointOnGeometryLocator.java deleted file mode 100644 index ff841c0279..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/locate/PointOnGeometryLocator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm.locate; - -import com.vividsolutions.jts.geom.*; - -/** - * An interface for classes which determine the {@link Location} of - * points in a {@link Geometry}. - * - * @author Martin Davis - */ -public interface PointOnGeometryLocator -{ - /** - * Determines the {@link Location} of a point in the {@link Geometry}. - * - * @param p the point to test - * @return the location of the point in the geometry - */ - int locate(Coordinate p); -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/locate/SimplePointInAreaLocator.java b/src/main/java/com/vividsolutions/jts/algorithm/locate/SimplePointInAreaLocator.java deleted file mode 100644 index 602ad3dec6..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/locate/SimplePointInAreaLocator.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.algorithm.locate; - -import java.util.Iterator; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.*; - -/** - * Computes the location of points - * relative to a {@link Polygonal} {@link Geometry}, - * using a simple O(n) algorithm. - * This algorithm is suitable for use in cases where - * only one or a few points will be tested against a given area. - *

          - * The algorithm used is only guaranteed to return correct results - * for points which are not on the boundary of the Geometry. - * - * @version 1.7 - */ -public class SimplePointInAreaLocator - implements PointOnGeometryLocator -{ - - /** - * Determines the {@link Location} of a point in an areal {@link Geometry}. - * Currently this will never return a value of BOUNDARY. - * - * @param p the point to test - * @param geom the areal geometry to test - * @return the Location of the point in the geometry - */ - public static int locate(Coordinate p, Geometry geom) - { - if (geom.isEmpty()) return Location.EXTERIOR; - - if (containsPoint(p, geom)) - return Location.INTERIOR; - return Location.EXTERIOR; - } - - private static boolean containsPoint(Coordinate p, Geometry geom) - { - if (geom instanceof Polygon) { - return containsPointInPolygon(p, (Polygon) geom); - } - else if (geom instanceof GeometryCollection) { - Iterator geomi = new GeometryCollectionIterator((GeometryCollection) geom); - while (geomi.hasNext()) { - Geometry g2 = (Geometry) geomi.next(); - if (g2 != geom) - if (containsPoint(p, g2)) - return true; - } - } - return false; - } - - public static boolean containsPointInPolygon(Coordinate p, Polygon poly) - { - if (poly.isEmpty()) return false; - LinearRing shell = (LinearRing) poly.getExteriorRing(); - if (! isPointInRing(p, shell)) return false; - // now test if the point lies in or on the holes - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - LinearRing hole = (LinearRing) poly.getInteriorRingN(i); - if (isPointInRing(p, hole)) return false; - } - return true; - } - - /** - * Determines whether a point lies in a LinearRing, - * using the ring envelope to short-circuit if possible. - * - * @param p the point to test - * @param ring a linear ring - * @return true if the point lies inside the ring - */ - private static boolean isPointInRing(Coordinate p, LinearRing ring) - { - // short-circuit if point is not in ring envelope - if (! ring.getEnvelopeInternal().intersects(p)) - return false; - return CGAlgorithms.isPointInRing(p, ring.getCoordinates()); - } - - private Geometry geom; - - public SimplePointInAreaLocator(Geometry geom) { - this.geom = geom; - } - - public int locate(Coordinate p) { - return SimplePointInAreaLocator.locate(p, geom); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/match/AreaSimilarityMeasure.java b/src/main/java/com/vividsolutions/jts/algorithm/match/AreaSimilarityMeasure.java deleted file mode 100644 index 67ea103770..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/match/AreaSimilarityMeasure.java +++ /dev/null @@ -1,73 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm.match; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.distance.*; - -/** - * Measures the degree of similarity between two {@link Geometry}s - * using the area of intersection between the geometries. - * The measure is normalized to lie in the range [0, 1]. - * Higher measures indicate a great degree of similarity. - *

          - * NOTE: Currently experimental and incomplete. - * - * @author mbdavis - * - */ -public class AreaSimilarityMeasure - implements SimilarityMeasure -{ - /* - public static double measure(Geometry a, Geometry b) - { - AreaSimilarityMeasure gv = new AreaSimilarityMeasure(a, b); - return gv.measure(); - } - */ - - public AreaSimilarityMeasure() - { - } - - public double measure(Geometry g1, Geometry g2) - { - double areaInt = g1.intersection(g2).getArea(); - double areaUnion = g1.union(g2).getArea(); - return areaInt / areaUnion; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/match/HausdorffSimilarityMeasure.java b/src/main/java/com/vividsolutions/jts/algorithm/match/HausdorffSimilarityMeasure.java deleted file mode 100644 index 89b6bdcec8..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/match/HausdorffSimilarityMeasure.java +++ /dev/null @@ -1,95 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm.match; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.distance.*; - -/** - * Measures the degree of similarity between two {@link Geometry}s - * using the Hausdorff distance metric. - * The measure is normalized to lie in the range [0, 1]. - * Higher measures indicate a great degree of similarity. - *

          - * The measure is computed by computing the Hausdorff distance - * between the input geometries, and then normalizing - * this by dividing it by the diagonal distance across - * the envelope of the combined geometries. - * - * @author mbdavis - * - */ -public class HausdorffSimilarityMeasure - implements SimilarityMeasure -{ - /* - public static double measure(Geometry a, Geometry b) - { - HausdorffSimilarityMeasure gv = new HausdorffSimilarityMeasure(a, b); - return gv.measure(); - } - */ - - public HausdorffSimilarityMeasure() - { - } - - /* - * Densify a small amount to increase accuracy of Hausdorff distance - */ - private static final double DENSIFY_FRACTION = 0.25; - - public double measure(Geometry g1, Geometry g2) - { - double distance = DiscreteHausdorffDistance.distance(g1, g2, DENSIFY_FRACTION); - - Envelope env = new Envelope(g1.getEnvelopeInternal()); - env.expandToInclude(g2.getEnvelopeInternal()); - double envSize = diagonalSize(env); - // normalize so that more similarity produces a measure closer to 1 - double measure = 1 - distance / envSize; - - //System.out.println("Hausdorff distance = " + distance + ", measure = " + measure); - return measure; - } - - public static double diagonalSize(Envelope env) - { - if (env.isNull()) return 0.0; - - double width = env.getWidth(); - double hgt = env.getHeight(); - return Math.sqrt(width * width + hgt * hgt); - } -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasure.java b/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasure.java deleted file mode 100644 index 76a4cdab30..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasure.java +++ /dev/null @@ -1,55 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm.match; - -import com.vividsolutions.jts.geom.*; - -/** - * An interface for classes which measures the degree of similarity between two {@link Geometry}s. - * The computed measure lies in the range [0, 1]. - * Higher measures indicate a great degree of similarity. - * A measure of 1.0 indicates that the input geometries are identical - * A measure of 0.0 indicates that the geometries - * have essentially no similarity. - * The precise definition of "identical" and "no similarity" may depend on the - * exact algorithm being used. - * - * @author mbdavis - * - */ -public interface SimilarityMeasure -{ - - double measure(Geometry g1, Geometry g2); -} diff --git a/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasureCombiner.java b/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasureCombiner.java deleted file mode 100644 index c4fad0a800..0000000000 --- a/src/main/java/com/vividsolutions/jts/algorithm/match/SimilarityMeasureCombiner.java +++ /dev/null @@ -1,49 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.algorithm.match; - -/** - * Provides methods to mathematically combine {@link SimilarityMeasure} values. - * - * @author Martin Davis - * - */ -public class SimilarityMeasureCombiner -{ - public static double combine(double measure1, double measure2) - { - return Math.min(measure1, measure2); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/awt/FontGlyphReader.java b/src/main/java/com/vividsolutions/jts/awt/FontGlyphReader.java deleted file mode 100644 index dd6f590b65..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/FontGlyphReader.java +++ /dev/null @@ -1,137 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.awt; - -import java.util.*; -import java.awt.Font; -import java.awt.font.*; -import com.vividsolutions.jts.geom.*; - -/** - * Provides methods to read {@link Font} glyphs for strings - * into {@link Polygonal} geometry. - *

          - * It is suggested to use larger point sizes to render fonts glyphs, - * to reduce the effects of scale-dependent hints. - * The result geometry is in the base coordinate system of the font. - * The geometry can be further transformed as necessary using - * {@link AffineTransformation}s. - * - * @author Martin Davis - * - */ -public class FontGlyphReader -{ - /** - * The font name of the Java logical font Serif. - */ - public static final String FONT_SERIF = "Serif"; - - /** - * The font name of the Java logical font SansSerif. - *

          - * DEPRECATED - use FONT_SANSSERIF - */ - public static final String FONT_SANSERIF = "SansSerif"; - - - /** - * The font name of the Java logical font SansSerif. - */ - public static final String FONT_SANSSERIF = "SansSerif"; - - /** - * The font name of the Java logical font Monospaced. - */ - - public static final String FONT_MONOSPACED = "Monospaced"; - - // a flatness factor empirically determined to provide good results - private static final double FLATNESS_FACTOR = 400; - - /** - * Converts text rendered in the given font and pointsize to a {@link Geometry} - * using a standard flatness factor. - * - * @param text the text to render - * @param fontName the name of the font - * @param pointSize the pointSize to render at - * @param geomFact the geometryFactory to use to create the result - * @return a polygonal geometry representing the rendered text - */ - public static Geometry read(String text, String fontName, int pointSize, GeometryFactory geomFact) - { - return read(text, new Font(fontName, Font.PLAIN, pointSize), geomFact); - } - - /** - * Converts text rendered in the given {@link Font} to a {@link Geometry} - * using a standard flatness factor. - * - * @param text the text to render - * @param font the font to render with - * @param geomFact the geometryFactory to use to create the result - * @return a polygonal geometry representing the rendered text - */ - public static Geometry read(String text, Font font, GeometryFactory geomFact) - { - double flatness = font.getSize() / FLATNESS_FACTOR; - return read(text, font, flatness, geomFact); - } - - /** - * Converts text rendered in the given {@link Font} to a {@link Geometry} - * - * @param text the text to render - * @param font the font to render with - * @param flatness the flatness factor to use - * @param geomFact the geometryFactory to use to create the result - * @return a polygonal geometry representing the rendered text - */ - public static Geometry read(String text, Font font, double flatness, GeometryFactory geomFact) - { - char[] chs = text.toCharArray(); - FontRenderContext fontContext = new FontRenderContext(null, false, true); - GlyphVector gv = font.createGlyphVector(fontContext, chs); - List polys = new ArrayList(); - for (int i = 0; i < gv.getNumGlyphs(); i++) { - Geometry geom = ShapeReader.read(gv.getGlyphOutline(i), flatness, geomFact); - for (int j = 0; j < geom.getNumGeometries(); j++) { - polys.add(geom.getGeometryN(j)); - } - } - return geomFact.buildGeometry(polys); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/awt/GeometryCollectionShape.java b/src/main/java/com/vividsolutions/jts/awt/GeometryCollectionShape.java deleted file mode 100644 index 62475882f3..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/GeometryCollectionShape.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.awt; - -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * A {@link Shape} which contains a heterogeneous collection of other shapes - * representing JTS {@link Geometry}s. - * - * @author Martin Davis - * - */ -public class GeometryCollectionShape implements Shape { - private ArrayList shapes = new ArrayList(); - - public GeometryCollectionShape() { - } - - public void add(Shape shape) { - shapes.add(shape); - } - - public Rectangle getBounds() { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method getBounds() not yet implemented."); - } - - public Rectangle2D getBounds2D() { - Rectangle2D rectangle = null; - - for (Iterator i = shapes.iterator(); i.hasNext();) { - Shape shape = (Shape) i.next(); - - if (rectangle == null) { - rectangle = shape.getBounds2D(); - } else { - rectangle.add(shape.getBounds2D()); - } - } - - return rectangle; - } - - public boolean contains(double x, double y) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method contains() not yet implemented."); - } - - public boolean contains(Point2D p) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method contains() not yet implemented."); - } - - public boolean intersects(double x, double y, double w, double h) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method intersects() not yet implemented."); - } - - public boolean intersects(Rectangle2D r) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method intersects() not yet implemented."); - } - - public boolean contains(double x, double y, double w, double h) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method contains() not yet implemented."); - } - - public boolean contains(Rectangle2D r) { - /**@todo Implement this java.awt.Shape method*/ - throw new java.lang.UnsupportedOperationException( - "Method contains() not yet implemented."); - } - - public PathIterator getPathIterator(AffineTransform at) { - return new ShapeCollectionPathIterator(shapes, at); - } - - public PathIterator getPathIterator(AffineTransform at, double flatness) { - // since Geometry is linear, can simply delegate to the simple method - return getPathIterator(at); - } -} diff --git a/src/main/java/com/vividsolutions/jts/awt/IdentityPointTransformation.java b/src/main/java/com/vividsolutions/jts/awt/IdentityPointTransformation.java deleted file mode 100644 index c3dfabb3df..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/IdentityPointTransformation.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.geom.Point2D; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Copies point ordinates with no transformation. - * - * @author Martin Davis - * - */ -public class IdentityPointTransformation -implements PointTransformation -{ - public void transform(Coordinate model, Point2D view) - { - view.setLocation(model.x, model.y); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/awt/PointShapeFactory.java b/src/main/java/com/vividsolutions/jts/awt/PointShapeFactory.java deleted file mode 100644 index 1f2e826849..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/PointShapeFactory.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.Shape; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * An interface for classes which create {@link Shape}s to represent - * {@link Point} - * geometries. Java2D does not provide an actual point shape, so some other - * shape must be used to render points (e.g. such as a Rectangle or Ellipse). - * - * @author Martin Davis - * - */ -public interface PointShapeFactory { - /** - * Creates a shape representing a {@link Point}. - * - * @param point - * the location of the point - * @return a shape - */ - Shape createPoint(Point2D point); - - public static abstract class BasePointShapeFactory implements - PointShapeFactory { - /** - * The default size of the shape - */ - public static final double DEFAULT_SIZE = 3.0; - - protected double size = DEFAULT_SIZE; - - /** - * Creates a new factory for points with default size. - * - */ - public BasePointShapeFactory() { - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public BasePointShapeFactory(double size) { - this.size = size; - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public abstract Shape createPoint(Point2D point); - } - - public static class Point extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public Point() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public Point(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - Line2D.Double pointMarker = - new Line2D.Double( - point.getX(), - point.getY(), - point.getX(), - point.getY()); - return pointMarker; - } - } - - public static class Square extends BasePointShapeFactory { - /** - * Creates a new factory for squares with default size. - * - */ - public Square() { - super(); - } - - /** - * Creates a factory for squares of given size. - * - * @param size - * the size of the points - */ - public Square(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - Rectangle2D.Double pointMarker = - new Rectangle2D.Double( - 0.0, - 0.0, - size, - size); - pointMarker.x = (double) (point.getX() - (size / 2)); - pointMarker.y = (double) (point.getY() - (size / 2)); - - return pointMarker; - } - } - - public static class Star extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public Star() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public Star(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - GeneralPath path = new GeneralPath(); - path.moveTo((float) point.getX(), (float) (point.getY() - size/2)); - path.lineTo((float) (point.getX() + size * 1/8), (float) (point.getY() - size * 1/8)); - path.lineTo((float) (point.getX() + size/2), (float) (point.getY() - size * 1/8)); - path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() + size * 1/8)); - path.lineTo((float) (point.getX() + size * 3/8), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX()), (float) (point.getY() + size * 2/8)); - path.lineTo((float) (point.getX() - size * 3/8), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() + size * 1/8)); - path.lineTo((float) (point.getX() - size/2), (float) (point.getY() - size * 1/8)); - path.lineTo((float) (point.getX() - size * 1/8), (float) (point.getY() - size * 1/8)); - path.closePath(); - return path; - } - } - - public static class Triangle extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public Triangle() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public Triangle(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - - GeneralPath path = new GeneralPath(); - path.moveTo((float) (point.getX()), (float) (point.getY() - size / 2)); - path.lineTo((float) (point.getX() + size / 2), (float) (point.getY() + size / 2)); - path.lineTo((float) (point.getX() - size / 2), (float) (point.getY() + size / 2)); - path.lineTo((float) (point.getX()), (float) (point.getY() - size / 2)); - - return path; - } - - } - public static class Circle extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public Circle() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public Circle(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - Ellipse2D.Double pointMarker = - new Ellipse2D.Double( - 0.0, - 0.0, - size, - size); - pointMarker.x = (double) (point.getX() - (size / 2)); - pointMarker.y = (double) (point.getY() - (size / 2)); - - return pointMarker; - } - - } - public static class Cross extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public Cross() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public Cross(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - - float x1 = (float) (point.getX() - size/2f); - float x2 = (float) (point.getX() - size/4f); - float x3 = (float) (point.getX() + size/4f); - float x4 = (float) (point.getX() + size/2f); - - float y1 = (float) (point.getY() - size/2f); - float y2 = (float) (point.getY() - size/4f); - float y3 = (float) (point.getY() + size/4f); - float y4 = (float) (point.getY() + size/2f); - - GeneralPath path = new GeneralPath(); - path.moveTo(x2, y1); - path.lineTo(x3, y1); - path.lineTo(x3, y2); - path.lineTo(x4, y2); - path.lineTo(x4, y3); - path.lineTo(x3, y3); - path.lineTo(x3, y4); - path.lineTo(x2, y4); - path.lineTo(x2, y3); - path.lineTo(x1, y3); - path.lineTo(x1, y2); - path.lineTo(x2, y2); - path.lineTo(x2, y1); - - return path; - } - - } - public static class X extends BasePointShapeFactory { - /** - * Creates a new factory for points with default size. - * - */ - public X() { - super(); - } - - /** - * Creates a factory for points of given size. - * - * @param size - * the size of the points - */ - public X(double size) { - super(size); - } - - /** - * Creates a shape representing a point. - * - * @param point - * the location of the point - * @return a shape - */ - public Shape createPoint(Point2D point) { - GeneralPath path = new GeneralPath(); - path.moveTo((float) (point.getX()), (float) (point.getY() - size * 1/8)); - path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() - size/2)); - path.lineTo((float) (point.getX() + size/2), (float) (point.getY() - size/2)); - path.lineTo((float) (point.getX() + size * 1/8), (float) (point.getY())); - path.lineTo((float) (point.getX() + size/2), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX()), (float) (point.getY() + size * 1/8)); - path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX() - size/2), (float) (point.getY() + size/2)); - path.lineTo((float) (point.getX() - size * 1/8), (float) (point.getY())); - path.lineTo((float) (point.getX() - size/2), (float) (point.getY() - size/2)); - path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() - size/2)); - path.closePath(); - return path; - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/awt/PointTransformation.java b/src/main/java/com/vividsolutions/jts/awt/PointTransformation.java deleted file mode 100644 index f742fdf380..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/PointTransformation.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.geom.Point2D; -import com.vividsolutions.jts.geom.*; - -/** - * Transforms a geometry {@link Coordinate} into a Java2D {@link Point}, - * possibly with a mathematical transformation of the ordinate values. - * Transformation from a model coordinate system to a view coordinate system - * can be efficiently performed by supplying an appropriate transformation. - * - * @author Martin Davis - */ -public interface PointTransformation { - /** - * Transforms a {@link Coordinate} into a Java2D {@link Point}. - * - * @param src the source Coordinate - * @param dest the destination Point - */ - public void transform(Coordinate src, Point2D dest); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/awt/PolygonShape.java b/src/main/java/com/vividsolutions/jts/awt/PolygonShape.java deleted file mode 100644 index 7087f6e064..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/PolygonShape.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.Collection; -import java.util.Iterator; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A {@link Shape} which represents a polygon which may contain holes. - * Provided because the standard AWT Polygon class does not support holes. - * - * @author Martin Davis - * - */ -public class PolygonShape implements Shape -{ - // use a GeneralPath with a winding rule, since it supports floating point coordinates - private GeneralPath polygonPath; - private GeneralPath ringPath; - - /** - * Creates a new polygon {@link Shape}. - * - * @param shellVertices the vertices of the shell - * @param holeVerticesCollection a collection of Coordinate[] for each hole - */ - public PolygonShape(Coordinate[] shellVertices, - Collection holeVerticesCollection) - { - polygonPath = toPath(shellVertices); - - for (Iterator i = holeVerticesCollection.iterator(); i.hasNext();) { - Coordinate[] holeVertices = (Coordinate[]) i.next(); - polygonPath.append(toPath(holeVertices), false); - } - } - - public PolygonShape() - { - } - - void addToRing(Point2D p) - { - if (ringPath == null) { - ringPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - ringPath.moveTo((float) p.getX(), (float) p.getY()); - } - else { - ringPath.lineTo((float) p.getX(), (float) p.getY()); - } - } - - void endRing() - { - ringPath.closePath(); - if (polygonPath == null) { - polygonPath = ringPath; - } - else { - polygonPath.append(ringPath, false); - } - ringPath = null; - } - - /** - * Creates a GeneralPath representing a polygon ring - * having the given coordinate sequence. - * Uses the GeneralPath.WIND_EVEN_ODD winding rule. - * - * @param coordinates a coordinate sequence - * @return the path for the coordinate sequence - */ - private GeneralPath toPath(Coordinate[] coordinates) { - GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, coordinates.length); - - if (coordinates.length > 0) { - path.moveTo((float) coordinates[0].x, (float) coordinates[0].y); - for (int i = 0; i < coordinates.length; i++) { - path.lineTo((float) coordinates[i].x, (float) coordinates[i].y); - } - } - return path; - } - - public Rectangle getBounds() { - return polygonPath.getBounds(); - } - - public Rectangle2D getBounds2D() { - return polygonPath.getBounds2D(); - } - - public boolean contains(double x, double y) { - return polygonPath.contains(x, y); - } - - public boolean contains(Point2D p) { - return polygonPath.contains(p); - } - - public boolean intersects(double x, double y, double w, double h) { - return polygonPath.intersects(x, y, w, h); - } - - public boolean intersects(Rectangle2D r) { - return polygonPath.intersects(r); - } - - public boolean contains(double x, double y, double w, double h) { - return polygonPath.contains(x, y, w, h); - } - - public boolean contains(Rectangle2D r) { - return polygonPath.contains(r); - } - - public PathIterator getPathIterator(AffineTransform at) { - return polygonPath.getPathIterator(at); - } - - public PathIterator getPathIterator(AffineTransform at, double flatness) { - return getPathIterator(at, flatness); - } -} diff --git a/src/main/java/com/vividsolutions/jts/awt/ShapeCollectionPathIterator.java b/src/main/java/com/vividsolutions/jts/awt/ShapeCollectionPathIterator.java deleted file mode 100644 index 67b5bdf0f2..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/ShapeCollectionPathIterator.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.PathIterator; -import java.util.Collection; -import java.util.Iterator; - -/** - * A {@link PathIterator} which provides paths for a collection of {@link Shape}s. - * - * @author Martin Davis - */ -public class ShapeCollectionPathIterator implements PathIterator { - private Iterator shapeIterator; - - // initialize with a no-op iterator - private PathIterator currentPathIterator = new PathIterator() { - public int getWindingRule() { - throw new UnsupportedOperationException(); - } - - public boolean isDone() { - return true; - } - - public void next() { - } - - public int currentSegment(float[] coords) { - throw new UnsupportedOperationException(); - } - - public int currentSegment(double[] coords) { - throw new UnsupportedOperationException(); - } - }; - - private AffineTransform affineTransform; - private boolean done = false; - - /** - * Creates a new path iterator for a collection of {@link Shape}s. - * - * @param shapes the Shapes in the collection - * @param affineTransform a optional transformation to be applied to the coordinates in the path (may be null) - */ - public ShapeCollectionPathIterator(Collection shapes, - AffineTransform affineTransform) { - shapeIterator = shapes.iterator(); - this.affineTransform = affineTransform; - next(); - } - - public int getWindingRule() { - /** - * WIND_NON_ZERO is more accurate than WIND_EVEN_ODD, and can be comparable - * in speed. (See http://www.geometryalgorithms.com/Archive/algorithm_0103/algorithm_0103.htm#Winding%20Number) - * However, WIND_NON_ZERO requires that the - * shell and holes be oriented in a certain way. - * So use WIND_EVEN_ODD. - */ - return PathIterator.WIND_EVEN_ODD; - } - - public boolean isDone() { - return done; - } - - public void next() { - currentPathIterator.next(); - - if (currentPathIterator.isDone() && !shapeIterator.hasNext()) { - done = true; - return; - } - if (currentPathIterator.isDone()) { - currentPathIterator = ((Shape) shapeIterator.next()).getPathIterator(affineTransform); - } - } - - public int currentSegment(float[] coords) { - return currentPathIterator.currentSegment(coords); - } - - public int currentSegment(double[] coords) { - return currentPathIterator.currentSegment(coords); - } -} diff --git a/src/main/java/com/vividsolutions/jts/awt/ShapeReader.java b/src/main/java/com/vividsolutions/jts/awt/ShapeReader.java deleted file mode 100644 index 62a49a2f7c..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/ShapeReader.java +++ /dev/null @@ -1,193 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.awt; - -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.PathIterator; -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; - -/** - * Converts a Java2D {@link Shape} - * or the more general {@link PathIterator} into a {@link Geometry}. - *

          - * The coordinate system for Java2D is typically screen coordinates, - * which has the Y axis inverted - * relative to the usual JTS coordinate system. - * This is rectified during conversion. - *

          - * PathIterators to be converted are expected to be linear or flat. - * That is, they should contain only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE segment types. - * Any other segment types will cause an exception. - * - * @author Martin Davis - * - */ -public class ShapeReader -{ - private static final AffineTransform INVERT_Y = AffineTransform.getScaleInstance(1, -1); - - /** - * Converts a flat path to a {@link Geometry}. - * - * @param pathIt the path to convert - * @param geomFact the GeometryFactory to use - * @return a Geometry representing the path - */ - public static Geometry read(PathIterator pathIt, GeometryFactory geomFact) - { - ShapeReader pc = new ShapeReader(geomFact); - return pc.read(pathIt); - } - - /** - * Converts a Shape to a Geometry, flattening it first. - * - * @param shp the Java2D shape - * @param flatness the flatness parameter to use - * @param geomFact the GeometryFactory to use - * @return a Geometry representing the shape - */ - public static Geometry read(Shape shp, double flatness, GeometryFactory geomFact) - { - PathIterator pathIt = shp.getPathIterator(INVERT_Y, flatness); - return ShapeReader.read(pathIt, geomFact); - } - - private GeometryFactory geometryFactory; - - public ShapeReader(GeometryFactory geometryFactory) { - this.geometryFactory = geometryFactory; - } - - /** - * Converts a flat path to a {@link Geometry}. - * - * @param pathIt the path to convert - * @return a Geometry representing the path - */ - public Geometry read(PathIterator pathIt) - { - List pathPtSeq = toCoordinates(pathIt); - - List polys = new ArrayList(); - int seqIndex = 0; - while (seqIndex < pathPtSeq.size()) { - // assume next seq is shell - // TODO: test this - Coordinate[] pts = (Coordinate[]) pathPtSeq.get(seqIndex); - LinearRing shell = geometryFactory.createLinearRing(pts); - seqIndex++; - - List holes = new ArrayList(); - // add holes as long as rings are CCW - while (seqIndex < pathPtSeq.size() && isHole((Coordinate[]) pathPtSeq.get(seqIndex))) { - Coordinate[] holePts = (Coordinate[]) pathPtSeq.get(seqIndex); - LinearRing hole = geometryFactory.createLinearRing(holePts); - holes.add(hole); - seqIndex++; - } - LinearRing[] holeArray = GeometryFactory.toLinearRingArray(holes); - polys.add(geometryFactory.createPolygon(shell, holeArray)); - } - return geometryFactory.buildGeometry(polys); - } - - private boolean isHole(Coordinate[] pts) - { - return CGAlgorithms.isCCW(pts); - } - - /** - * Extracts the points of the paths in a flat {@link PathIterator} into - * a list of Coordinate arrays. - * - * @param pathIt a path iterator - * @return a List of Coordinate arrays - * @throws IllegalArgumentException if a non-linear segment type is encountered - */ - public static List toCoordinates(PathIterator pathIt) - { - List coordArrays = new ArrayList(); - while (! pathIt.isDone()) { - Coordinate[] pts = nextCoordinateArray(pathIt); - if (pts == null) - break; - coordArrays.add(pts); - } - return coordArrays; - } - - private static Coordinate[] nextCoordinateArray(PathIterator pathIt) - { - double[] pathPt = new double[6]; - CoordinateList coordList = null; - boolean isDone = false; - while (! pathIt.isDone()) { - int segType = pathIt.currentSegment(pathPt); - switch (segType) { - case PathIterator.SEG_MOVETO: - if (coordList != null) { - // don't advance pathIt, to retain start of next path if any - isDone = true; - } - else { - coordList = new CoordinateList(); - coordList.add(new Coordinate(pathPt[0], pathPt[1])); - pathIt.next(); - } - break; - case PathIterator.SEG_LINETO: - coordList.add(new Coordinate(pathPt[0], pathPt[1])); - pathIt.next(); - break; - case PathIterator.SEG_CLOSE: - coordList.closeRing(); - pathIt.next(); - isDone = true; - break; - default: - throw new IllegalArgumentException("unhandled (non-linear) segment type encountered"); - } - if (isDone) - break; - } - return coordList.toCoordinateArray(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/awt/ShapeWriter.java b/src/main/java/com/vividsolutions/jts/awt/ShapeWriter.java deleted file mode 100644 index 4acb572446..0000000000 --- a/src/main/java/com/vividsolutions/jts/awt/ShapeWriter.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.awt; - -import java.awt.Shape; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.util.ArrayList; - -import com.vividsolutions.jts.geom.*; - - -/** - * Writes {@link Geometry}s into Java2D {@link Shape} objects - * of the appropriate type. - * This supports rendering geometries using Java2D. - * The ShapeWriter allows supplying a {@link PointTransformation} - * class, to transform coordinates from model space into view space. - * This is useful if a client is providing its own transformation - * logic, rather than relying on Java2D AffineTransforms. - *

          - * The writer supports removing duplicate consecutive points - * (via the {@link #setRemoveDuplicatePoints(boolean)} method) - * as well as true decimation - * (via the {@link #setDecimation(double)} method. - * Enabling one of these strategies can substantially improve - * rendering speed for large geometries. - * It is only necessary to enable one strategy. - * Using decimation is preferred, but this requires - * determining a distance below which input geometry vertices - * can be considered unique (which may not always be feasible). - * If neither strategy is enabled, all vertices - * of the input Geometry - * will be represented in the output Shape. - *

          - * - */ -public class ShapeWriter -{ - /** - * The point transformation used by default. - */ - public static final PointTransformation DEFAULT_POINT_TRANSFORMATION = new IdentityPointTransformation(); - - /** - * The point shape factory used by default. - */ - public static final PointShapeFactory DEFAULT_POINT_FACTORY = new PointShapeFactory.Square(3.0); - - private PointTransformation pointTransformer = DEFAULT_POINT_TRANSFORMATION; - private PointShapeFactory pointFactory = DEFAULT_POINT_FACTORY; - - /** - * Cache a Point2D object to use to transfer coordinates into shape - */ - private Point2D transPoint = new Point2D.Double(); - - /** - * If true, decimation will be used to reduce the number of vertices - * by removing consecutive duplicates. - * - */ - private boolean doRemoveDuplicatePoints = false; - - private double decimationDistance = 0; - - /** - * Creates a new ShapeWriter with a specified point transformation - * and point shape factory. - * - * @param pointTransformer a transformation from model to view space to use - * @param pointFactory the PointShapeFactory to use - */ - public ShapeWriter(PointTransformation pointTransformer, PointShapeFactory pointFactory) - { - if (pointTransformer != null) - this.pointTransformer = pointTransformer; - if (pointFactory != null) - this.pointFactory = pointFactory; - } - - /** - * Creates a new ShapeWriter with a specified point transformation - * and the default point shape factory. - * - * @param pointTransformer a transformation from model to view space to use - */ - public ShapeWriter(PointTransformation pointTransformer) - { - this(pointTransformer, null); - } - - /** - * Creates a new ShapeWriter with the default (identity) point transformation. - * - */ - public ShapeWriter() { - } - - /** - * Sets whether duplicate consecutive points should be eliminated. - * This can reduce the size of the generated Shapes - * and improve rendering speed, especially in situations - * where a transform reduces the extent of the geometry. - *

          - * The default is false. - * - * @param doDecimation whether decimation is to be used - */ - public void setRemoveDuplicatePoints(boolean doRemoveDuplicatePoints) - { - this.doRemoveDuplicatePoints = doRemoveDuplicatePoints; - } - - /** - * Sets the decimation distance used to determine - * whether vertices of the input geometry are - * considered to be duplicate and thus removed. - * The distance is axis distance, not Euclidean distance. - * The distance is specified in the input geometry coordinate system - * (NOT the transformed output coordinate system). - *

          - * When rendering to a screen image, a suitably small distance should be used - * to avoid obvious rendering defects. - * A distance equivalent to the equivalent of 1.5 pixels or less is recommended - * (and perhaps even smaller to avoid any chance of visible artifacts). - *

          - * The default distance is 0.0, which disables decimation. - * - * @param decimationDistance the distance below which vertices are considered to be duplicates - */ - public void setDecimation(double decimationDistance) - { - this.decimationDistance = decimationDistance; - } - - /** - * Creates a {@link Shape} representing a {@link Geometry}, - * according to the specified PointTransformation - * and PointShapeFactory (if relevant). - *

          - * Note that Shapes do not - * preserve information about which elements in heterogeneous collections - * are 1D and which are 2D. - * For example, a GeometryCollection containing a ring and a - * disk will render as two disks if Graphics.fill is used, - * or as two rings if Graphics.draw is used. - * To avoid this issue use separate shapes for the components. - * - * @param geometry the geometry to convert - * @return a Shape representing the geometry - */ - public Shape toShape(Geometry geometry) - { - if (geometry.isEmpty()) return new GeneralPath(); - if (geometry instanceof Polygon) return toShape((Polygon) geometry); - if (geometry instanceof LineString) return toShape((LineString) geometry); - if (geometry instanceof MultiLineString) return toShape((MultiLineString) geometry); - if (geometry instanceof Point) return toShape((Point) geometry); - if (geometry instanceof GeometryCollection) return toShape((GeometryCollection) geometry); - - throw new IllegalArgumentException( - "Unrecognized Geometry class: " + geometry.getClass()); - } - - private Shape toShape(Polygon p) - { - PolygonShape poly = new PolygonShape(); - - appendRing(poly, p.getExteriorRing().getCoordinates()); - for (int j = 0; j < p.getNumInteriorRing(); j++) { - appendRing(poly, p.getInteriorRingN(j).getCoordinates()); - } - - return poly; - } - - private void appendRing(PolygonShape poly, Coordinate[] coords) - { - double prevx = Double.NaN; - double prevy = Double.NaN; - Coordinate prev = null; - - int n = coords.length - 1; - /** - * Don't include closing point. - * Ring path will be closed explicitly, which provides a - * more accurate path representation. - */ - for (int i = 0; i < n; i++) { - - if (decimationDistance > 0.0) { - boolean isDecimated = prev != null - && Math.abs(coords[i].x - prev.x) < decimationDistance - && Math.abs(coords[i].y - prev.y) < decimationDistance; - if (i < n && isDecimated) - continue; - prev = coords[i]; - } - - transformPoint(coords[i], transPoint); - - if (doRemoveDuplicatePoints) { - // skip duplicate points (except the last point) - boolean isDup = transPoint.getX() == prevx && transPoint.getY() == prevy; - if (i < n && isDup) - continue; - prevx = transPoint.getX(); - prevy = transPoint.getY(); - } - poly.addToRing(transPoint); - } - // handle closing point - poly.endRing(); - } - - private Shape toShape(GeometryCollection gc) - { - GeometryCollectionShape shape = new GeometryCollectionShape(); - // add components to GC shape - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = (Geometry) gc.getGeometryN(i); - shape.add(toShape(g)); - } - return shape; - } - - private GeneralPath toShape(MultiLineString mls) - { - GeneralPath path = new GeneralPath(); - - for (int i = 0; i < mls.getNumGeometries(); i++) { - LineString lineString = (LineString) mls.getGeometryN(i); - path.append(toShape(lineString), false); - } - return path; - } - - private GeneralPath toShape(LineString lineString) - { - GeneralPath shape = new GeneralPath(); - - Coordinate prev = lineString.getCoordinateN(0); - transformPoint(prev, transPoint); - shape.moveTo((float) transPoint.getX(), (float) transPoint.getY()); - - double prevx = (double) transPoint.getX(); - double prevy = (double) transPoint.getY(); - - int n = lineString.getNumPoints() - 1; - //int count = 0; - for (int i = 1; i <= n; i++) { - Coordinate currentCoord = lineString.getCoordinateN(i); - if (decimationDistance > 0.0) { - boolean isDecimated = prev != null - && Math.abs(currentCoord.x - prev.x) < decimationDistance - && Math.abs(currentCoord.y - prev.y) < decimationDistance; - if (i < n && isDecimated) { - continue; - } - prev = currentCoord; - } - - transformPoint(currentCoord, transPoint); - - if (doRemoveDuplicatePoints) { - // skip duplicate points (except the last point) - boolean isDup = transPoint.getX() == prevx && transPoint.getY() == prevy; - if (i < n && isDup) - continue; - prevx = transPoint.getX(); - prevy = transPoint.getY(); - //count++; - } - shape.lineTo((float) transPoint.getX(), (float) transPoint.getY()); - } - //System.out.println(count); - return shape; - } - - private Shape toShape(Point point) - { - Point2D viewPoint = transformPoint(point.getCoordinate()); - return pointFactory.createPoint(viewPoint); - } - - private Point2D transformPoint(Coordinate model) { - return transformPoint(model, new Point2D.Double()); - } - - private Point2D transformPoint(Coordinate model, Point2D view) { - pointTransformer.transform(model, view); - return view; - } -} diff --git a/src/main/java/com/vividsolutions/jts/densify/Densifier.java b/src/main/java/com/vividsolutions/jts/densify/Densifier.java deleted file mode 100644 index 38a8952d53..0000000000 --- a/src/main/java/com/vividsolutions/jts/densify/Densifier.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.densify; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.GeometryTransformer; - -/** - * Densifies a {@link Geometry} by inserting extra vertices along the line segments - * contained in the geometry. - * All segments in the created densified geometry will be no longer than - * than the given distance tolerance. - * Densified polygonal geometries are guaranteed to be topologically correct. - * The coordinates created during densification respect the input geometry's - * {@link PrecisionModel}. - *

          - * Note: At some future point this class will - * offer a variety of densification strategies. - * - * @author Martin Davis - */ -public class Densifier { - /** - * Densifies a geometry using a given distance tolerance, - * and respecting the input geometry's {@link PrecisionModel}. - * - * @param geom the geometry to densify - * @param distanceTolerance the distance tolerance to densify - * @return the densified geometry - */ - public static Geometry densify(Geometry geom, double distanceTolerance) { - Densifier densifier = new Densifier(geom); - densifier.setDistanceTolerance(distanceTolerance); - return densifier.getResultGeometry(); - } - - /** - * Densifies a coordinate sequence. - * - * @param pts - * @param distanceTolerance - * @return the densified coordinate sequence - */ - private static Coordinate[] densifyPoints(Coordinate[] pts, - double distanceTolerance, PrecisionModel precModel) { - LineSegment seg = new LineSegment(); - CoordinateList coordList = new CoordinateList(); - for (int i = 0; i < pts.length - 1; i++) { - seg.p0 = pts[i]; - seg.p1 = pts[i + 1]; - coordList.add(seg.p0, false); - double len = seg.getLength(); - int densifiedSegCount = (int) (len / distanceTolerance) + 1; - if (densifiedSegCount > 1) { - double densifiedSegLen = len / densifiedSegCount; - for (int j = 1; j < densifiedSegCount; j++) { - double segFract = (j * densifiedSegLen) / len; - Coordinate p = seg.pointAlong(segFract); - precModel.makePrecise(p); - coordList.add(p, false); - } - } - } - coordList.add(pts[pts.length - 1], false); - return coordList.toCoordinateArray(); - } - - private Geometry inputGeom; - - private double distanceTolerance; - - /** - * Creates a new densifier instance. - * - * @param inputGeom - */ - public Densifier(Geometry inputGeom) { - this.inputGeom = inputGeom; - } - - /** - * Sets the distance tolerance for the densification. All line segments - * in the densified geometry will be no longer than the distance tolereance. - * simplified geometry will be within this distance of the original geometry. - * The distance tolerance must be positive. - * - * @param distanceTolerance - * the densification tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - if (distanceTolerance <= 0.0) - throw new IllegalArgumentException("Tolerance must be positive"); - this.distanceTolerance = distanceTolerance; - } - - /** - * Gets the densified geometry. - * - * @return the densified geometry - */ - public Geometry getResultGeometry() { - return (new DensifyTransformer()).transform(inputGeom); - } - - class DensifyTransformer extends GeometryTransformer { - protected CoordinateSequence transformCoordinates( - CoordinateSequence coords, Geometry parent) { - Coordinate[] inputPts = coords.toCoordinateArray(); - Coordinate[] newPts = Densifier - .densifyPoints(inputPts, distanceTolerance, parent.getPrecisionModel()); - // prevent creation of invalid linestrings - if (parent instanceof LineString && newPts.length == 1) { - newPts = new Coordinate[0]; - } - return factory.getCoordinateSequenceFactory().create(newPts); - } - - protected Geometry transformPolygon(Polygon geom, Geometry parent) { - Geometry roughGeom = super.transformPolygon(geom, parent); - // don't try and correct if the parent is going to do this - if (parent instanceof MultiPolygon) { - return roughGeom; - } - return createValidArea(roughGeom); - } - - protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) { - Geometry roughGeom = super.transformMultiPolygon(geom, parent); - return createValidArea(roughGeom); - } - - /** - * Creates a valid area geometry from one that possibly has bad topology - * (i.e. self-intersections). Since buffer can handle invalid topology, but - * always returns valid geometry, constructing a 0-width buffer "corrects" - * the topology. Note this only works for area geometries, since buffer - * always returns areas. This also may return empty geometries, if the input - * has no actual area. - * - * @param roughAreaGeom - * an area geometry possibly containing self-intersections - * @return a valid area geometry - */ - private Geometry createValidArea(Geometry roughAreaGeom) { - return roughAreaGeom.buffer(0.0); - } - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/dissolve/DissolveEdgeGraph.java b/src/main/java/com/vividsolutions/jts/dissolve/DissolveEdgeGraph.java deleted file mode 100644 index 341d8b5690..0000000000 --- a/src/main/java/com/vividsolutions/jts/dissolve/DissolveEdgeGraph.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.vividsolutions.jts.dissolve; - -import com.vividsolutions.jts.edgegraph.EdgeGraph; -import com.vividsolutions.jts.edgegraph.HalfEdge; -import com.vividsolutions.jts.geom.Coordinate; - - -/** - * A graph containing {@link DissolveHalfEdge}s. - * - * @author Martin Davis - * - */ -class DissolveEdgeGraph extends EdgeGraph -{ - protected HalfEdge createEdge(Coordinate p0) - { - return new DissolveHalfEdge(p0); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/dissolve/DissolveHalfEdge.java b/src/main/java/com/vividsolutions/jts/dissolve/DissolveHalfEdge.java deleted file mode 100644 index 67b32c4148..0000000000 --- a/src/main/java/com/vividsolutions/jts/dissolve/DissolveHalfEdge.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.vividsolutions.jts.dissolve; - -import com.vividsolutions.jts.edgegraph.MarkHalfEdge; -import com.vividsolutions.jts.geom.Coordinate; - - -/** - * A HalfEdge which carries information - * required to support {@link LineDissolver}. - * - * @author Martin Davis - * - */ -class DissolveHalfEdge extends MarkHalfEdge -{ - private boolean isStart = false; - - public DissolveHalfEdge(Coordinate orig) { - super(orig); - } - - /** - * Tests whether this edge is the starting segment - * in a LineString being dissolved. - * - * @return true if this edge is a start segment - */ - public boolean isStart() - { - return isStart; - } - - /** - * Sets this edge to be the start segment of an input LineString. - */ - public void setStart() - { - isStart = true; - } -} diff --git a/src/main/java/com/vividsolutions/jts/dissolve/LineDissolver.java b/src/main/java/com/vividsolutions/jts/dissolve/LineDissolver.java deleted file mode 100644 index a6e013aedd..0000000000 --- a/src/main/java/com/vividsolutions/jts/dissolve/LineDissolver.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.vividsolutions.jts.dissolve; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - - -import com.vividsolutions.jts.edgegraph.HalfEdge; -import com.vividsolutions.jts.edgegraph.MarkHalfEdge; -import com.vividsolutions.jts.geom.CoordinateList; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryComponentFilter; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; - -/** - * Dissolves the linear components - * from a collection of {@link Geometry}s - * into a set of maximal-length {@link Linestring}s - * in which every unique segment appears once only. - * The output linestrings run between node vertices - * of the input, which are vertices which have - * either degree 1, or degree 3 or greater. - *

          - * Use cases for dissolving linear components - * include generalization - * (in particular, simplifying polygonal coverages), - * and visualization - * (in particular, avoiding symbology conflicts when - * depicting shared polygon boundaries). - *

          - * This class does not node the input lines. - * If there are line segments crossing in the input, - * they will still cross in the output. - * - * @author Martin Davis - * - */ -public class LineDissolver -{ - /** - * Dissolves the linear components in a geometry. - * - * @param g the geometry to dissolve - * @return the dissolved lines - */ - public static Geometry dissolve(Geometry g) - { - LineDissolver d = new LineDissolver(); - d.add(g); - return d.getResult(); - } - - private Geometry result; - private GeometryFactory factory; - private DissolveEdgeGraph graph; - private List lines = new ArrayList(); - - public LineDissolver() - { - graph = new DissolveEdgeGraph(); - } - - /** - * Adds a {@link Geometry} to be dissolved. - * Any number of geometries may be adde by calling this method multiple times. - * Any type of Geometry may be added. The constituent linework will be - * extracted to be dissolved. - * - * @param geometry geometry to be line-merged - */ - public void add(Geometry geometry) { - geometry.apply(new GeometryComponentFilter() { - public void filter(Geometry component) { - if (component instanceof LineString) { - add((LineString)component); - } - } - }); - } - /** - * Adds a collection of Geometries to be processed. May be called multiple times. - * Any dimension of Geometry may be added; the constituent linework will be - * extracted. - * - * @param geometries the geometries to be line-merged - */ - public void add(Collection geometries) - { - for (Iterator i = geometries.iterator(); i.hasNext(); ) { - Geometry geometry = (Geometry) i.next(); - add(geometry); - } - } - - private void add(LineString lineString) { - if (factory == null) { - this.factory = lineString.getFactory(); - } - CoordinateSequence seq = lineString.getCoordinateSequence(); - boolean doneStart = false; - for (int i = 1; i < seq.size(); i++) { - DissolveHalfEdge e = (DissolveHalfEdge) graph.addEdge(seq.getCoordinate(i-1), seq.getCoordinate(i)); - // skip zero-length edges - if (e == null) continue; - /** - * Record source initial segments, so that they can be reflected in output when needed - * (i.e. during formation of isolated rings) - */ - if (! doneStart) { - e.setStart(); - doneStart = true; - } - } - } - - /** - * Gets the dissolved result as a MultiLineString. - * - * @return the dissolved lines - */ - public Geometry getResult() - { - if (result == null) - computeResult(); - return result; - } - - private void computeResult() { - Collection edges = graph.getVertexEdges(); - for (Iterator i = edges.iterator(); i.hasNext(); ) { - HalfEdge e = (HalfEdge) i.next(); - if (MarkHalfEdge.isMarked(e)) continue; - process(e); - } - result = factory.buildGeometry(lines); - } - - private Stack nodeEdgeStack = new Stack(); - - private void process(HalfEdge e) { - HalfEdge eNode = e.prevNode(); - // if edge is in a ring, just process this edge - if (eNode == null) - eNode = e; - stackEdges(eNode); - // extract lines from node edges in stack - buildLines(); - } - - /** - * For each edge in stack - * (which must originate at a node) - * extracts the line it initiates. - */ - private void buildLines() { - while (! nodeEdgeStack.empty()) { - HalfEdge e = (HalfEdge) nodeEdgeStack.pop(); - if (MarkHalfEdge.isMarked(e)) - continue; - buildLine(e); - } - } - - private DissolveHalfEdge ringStartEdge; - - /** - * Updates the tracked ringStartEdge - * if the given edge has a lower origin - * (using the standard {@link Coordinate} ordering). - * - * Identifying the lowest starting node meets two goals: - *

            - *
          • It ensures that isolated input rings are created using the original node and orientation - *
          • For isolated rings formed from multiple input linestrings, - * it provides a canonical node and orientation for the output - * (rather than essentially random, and thus hard to test). - *
          - * - * @param e - */ - private void updateRingStartEdge(DissolveHalfEdge e) - { - if (! e.isStart()) { - e = (DissolveHalfEdge) e.sym(); - if (! e.isStart()) return; - } - // here e is known to be a start edge - if (ringStartEdge == null) { - ringStartEdge = e; - return; - } - if (e.orig().compareTo(ringStartEdge.orig()) < 0) { - ringStartEdge = e; - } - } - - /** - * Builds a line starting from the given edge. - * The start edge origin is a node (valence = 1 or >= 3), - * unless it is part of a pure ring. - * A pure ring has no other incident lines. - * In this case the start edge may occur anywhere on the ring. - * - * The line is built up to the next node encountered, - * or until the start edge is re-encountered - * (which happens if the edges form a ring). - * - * @param eStart - */ - private void buildLine(HalfEdge eStart) { - CoordinateList line = new CoordinateList(); - DissolveHalfEdge e = (DissolveHalfEdge) eStart; - ringStartEdge = null; - - MarkHalfEdge.markBoth(e); - line.add(e.orig().clone(), false); - // scan along the path until a node is found (if one exists) - while (e.sym().degree() == 2) { - updateRingStartEdge(e); - DissolveHalfEdge eNext = (DissolveHalfEdge) e.next(); - // check if edges form a ring - if so, we're done - if (eNext == eStart) { - buildRing(ringStartEdge); - return; - } - // add point to line, and move to next edge - line.add(eNext.orig().clone(), false); - e = eNext; - MarkHalfEdge.markBoth(e); - } - // add final node - line.add(e.dest().clone(), false); - - // queue up the final node edges - stackEdges(e.sym()); - // store the scanned line - addLine(line); - } - - private void buildRing(HalfEdge eStartRing) { - CoordinateList line = new CoordinateList(); - HalfEdge e = eStartRing; - - line.add(e.orig().clone(), false); - // scan along the path until a node is found (if one exists) - while (e.sym().degree() == 2) { - HalfEdge eNext = e.next(); - // check if edges form a ring - if so, we're done - if (eNext == eStartRing) - break; - - // add point to line, and move to next edge - line.add(eNext.orig().clone(), false); - e = eNext; - } - // add final node - line.add(e.dest().clone(), false); - - // store the scanned line - addLine(line); - } - - private void addLine(CoordinateList line) { - lines.add(factory.createLineString(line.toCoordinateArray())); - } - - /** - * Adds edges around this node to the stack. - * - * @param node - */ - private void stackEdges(HalfEdge node) { - HalfEdge e = node; - do { - if (! MarkHalfEdge.isMarked(e)) - nodeEdgeStack.add(e); - e = e.oNext(); - } while (e != node); - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraph.java b/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraph.java deleted file mode 100644 index ad445a02e8..0000000000 --- a/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraph.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.vividsolutions.jts.edgegraph; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A graph comprised of {@link HalfEdge}s. - * It supports tracking the vertices in the graph - * via edges incident on them, - * to allow efficient lookup of edges and vertices. - *

          - * This class may be subclassed to use a - * different subclass of HalfEdge, - * by overriding {@link #createEdge(Coordinate)}. - * If additional logic is required to initialize - * edges then {@link EdgeGraph#addEdge(Coordinate, Coordinate)} - * can be overridden as well. - * - * @author Martin Davis - * - */ -public class EdgeGraph -{ - private Map vertexMap = new HashMap(); - - public EdgeGraph() { - } - - /** - * Creates a single HalfEdge. - * Override to use a different HalfEdge subclass. - * - * @param orig the origin location - * @return a new HalfEdge with the given origin - */ - protected HalfEdge createEdge(Coordinate orig) - { - return new HalfEdge(orig); - } - - private HalfEdge create(Coordinate p0, Coordinate p1) - { - HalfEdge e0 = createEdge(p0); - HalfEdge e1 = createEdge(p1); - HalfEdge.init(e0, e1); - return e0; - } - - /** - * Adds an edge between the coordinates orig and dest - * to this graph. - * Only valid edges can be added (in particular, zero-length segments cannot be added) - * - * @param orig the edge origin location - * @param dest the edge destination location. - * @return the created edge - * @return null if the edge was invalid and not added - * - * @see {@link #isValidEdge(Coordinate, Coordinate)} - */ - public HalfEdge addEdge(Coordinate orig, Coordinate dest) { - if (! isValidEdge(orig, dest)) return null; - - /** - * Attempt to find the edge already in the graph. - * Return it if found. - * Otherwise, use a found edge with same origin (if any) to construct new edge. - */ - HalfEdge eAdj = (HalfEdge) vertexMap.get(orig); - HalfEdge eSame = null; - if (eAdj != null) { - eSame = eAdj.find(dest); - } - if (eSame != null) { - return eSame; - } - - HalfEdge e = insert(orig, dest, eAdj); - return e; - } - - /** - * Tests if the given coordinates form a valid edge (with non-zero length). - * - * @param orig the start coordinate - * @param dest the end coordinate - * @return true if the edge formed is valid - */ - public static boolean isValidEdge(Coordinate orig, Coordinate dest) { - int cmp = dest.compareTo(orig); - return cmp != 0; - } - - /** - * Inserts an edge not already present into the graph. - * - * @param orig the edge origin location - * @param dest the edge destination location - * @param eAdj an existing edge with same orig (if any) - * @return the created edge - */ - private HalfEdge insert(Coordinate orig, Coordinate dest, HalfEdge eAdj) { - // edge does not exist, so create it and insert in graph - HalfEdge e = create(orig, dest); - if (eAdj != null) { - eAdj.insert(e); - } - else { - // add halfedges to to map - vertexMap.put(orig, e); - } - - HalfEdge eAdjDest = (HalfEdge) vertexMap.get(dest); - if (eAdjDest != null) { - eAdjDest.insert(e.sym()); - } - else { - vertexMap.put(dest, e.sym()); - } - return e; - } - - public Collection getVertexEdges() - { - return vertexMap.values(); - } - - /** - * Finds an edge in this graph with the given origin - * and destination, if one exists. - * - * @param orig the origin location - * @param dest the destination location. - * @return an edge with the given orig and dest, or null if none exists - */ - public HalfEdge findEdge(Coordinate orig, Coordinate dest) { - HalfEdge e = (HalfEdge) vertexMap.get(orig); - if (e == null) return null; - return e.find(dest); - } -} diff --git a/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraphBuilder.java b/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraphBuilder.java deleted file mode 100644 index 1932686ef8..0000000000 --- a/src/main/java/com/vividsolutions/jts/edgegraph/EdgeGraphBuilder.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.vividsolutions.jts.edgegraph; - -import java.util.Collection; -import java.util.Iterator; - -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryComponentFilter; -import com.vividsolutions.jts.geom.LineString; - -/** - * Builds an edge graph from geometries containing edges. - * - * @author mdavis - * - */ -public class EdgeGraphBuilder -{ - public static EdgeGraph build(Collection geoms) { - EdgeGraphBuilder builder = new EdgeGraphBuilder(); - builder.add(geoms); - return builder.getGraph(); - } - - private EdgeGraph graph = new EdgeGraph(); - - public EdgeGraphBuilder() - { - - } - - public EdgeGraph getGraph() - { - return graph; - } - - /** - * Adds the edges of a Geometry to the graph. - * May be called multiple times. - * Any dimension of Geometry may be added; the constituent edges are - * extracted. - * - * @param geometry geometry to be added - */ - public void add(Geometry geometry) { - geometry.apply(new GeometryComponentFilter() { - public void filter(Geometry component) { - if (component instanceof LineString) { - add((LineString)component); - } - } - }); - } - /** - * Adds the edges in a collection of {@link Geometry}s to the graph. - * May be called multiple times. - * Any dimension of Geometry may be added. - * - * @param geometries the geometries to be added - */ - public void add(Collection geometries) - { - for (Iterator i = geometries.iterator(); i.hasNext(); ) { - Geometry geometry = (Geometry) i.next(); - add(geometry); - } - } - - private void add(LineString lineString) { - CoordinateSequence seq = lineString.getCoordinateSequence(); - for (int i = 1; i < seq.size(); i++) { - graph.addEdge(seq.getCoordinate(i-1), seq.getCoordinate(i)); - } - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/edgegraph/HalfEdge.java b/src/main/java/com/vividsolutions/jts/edgegraph/HalfEdge.java deleted file mode 100644 index 3c0e4d262b..0000000000 --- a/src/main/java/com/vividsolutions/jts/edgegraph/HalfEdge.java +++ /dev/null @@ -1,351 +0,0 @@ -package com.vividsolutions.jts.edgegraph; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.Quadrant; -import com.vividsolutions.jts.util.Assert; - -/** - * Represents a directed component of an edge in an {@link EdgeGraph}. - * HalfEdges link vertices whose locations are defined by {@link Coordinate}s. - * HalfEdges start at an origin vertex, - * and terminate at a destination vertex. - * HalfEdges always occur in symmetric pairs, with the {@link #sym()} method - * giving access to the oppositely-oriented component. - * HalfEdges and the methods on them form an edge algebra, - * which can be used to traverse and query the topology - * of the graph formed by the edges. - *

          - * By design HalfEdges carry minimal information - * about the actual usage of the graph they represent. - * They can be subclassed to carry more information if required. - *

          - * HalfEdges form a complete and consistent data structure by themselves, - * but an {@link EdgeGraph} is useful to allow retrieving edges - * by vertex and edge location, as well as ensuring - * edges are created and linked appropriately. - * - * @author Martin Davis - * - */ -public class HalfEdge { - - /** - * Creates a HalfEdge pair representing an edge - * between two vertices located at coordinates p0 and p1. - * - * @param p0 a vertex coordinate - * @param p1 a vertex coordinate - * @return the HalfEdge with origin at p0 - */ - public static HalfEdge create(Coordinate p0, Coordinate p1) { - HalfEdge e0 = new HalfEdge(p0); - HalfEdge e1 = new HalfEdge(p1); - e0.init(e1); - return e0; - } - - /** - * Initialize a symmetric pair of halfedges. - * Intended for use by {@link EdgeGraph} subclasses. - * The edges are initialized to have each other - * as the {@link sym} edge, and to have {@link next} pointers - * which point to edge other. - * This effectively creates a graph containing a single edge. - * - * @param e0 a halfedge - * @param e1 a symmetric halfedge - * @return the initialized edge e0 - */ - public static HalfEdge init(HalfEdge e0, HalfEdge e1) - { - // ensure only newly created edges can be initialized, to prevent information loss - if (e0.sym != null || e1.sym != null - || e0.next != null || e1.next != null) - throw new IllegalStateException("Edges are already initialized"); - e0.init(e1); - return e0; - } - - private Coordinate orig; - private HalfEdge sym; - private HalfEdge next; - - /** - * Creates an edge originating from a given coordinate. - * - * @param orig the origin coordinate - */ - public HalfEdge(Coordinate orig) { - this.orig = orig; - } - - protected void init(HalfEdge e) - { - setSym(e); - e.setSym(this); - // set next ptrs for a single segment - setNext(e); - e.setNext(this); - } - - /** - * Gets the origin coordinate of this edge. - * - * @return the origin coordinate - */ - public Coordinate orig() { return orig; } - - /** - * Gets the destination coordinate of this edge. - * - * @return the destination coordinate - */ - public Coordinate dest() { return sym.orig; } - - /** - * Gets the symmetric pair edge of this edge. - * - * @return the symmetric pair edge - */ - public HalfEdge sym() - { - return sym; - } - - /** - * Sets the sym edge. - * - * @param e the sym edge to set - */ - private void setSym(HalfEdge e) { - sym = e; - } - - /** - * Gets the next edge CCW around the - * destination vertex of this edge. - * If the vertex has degree 1 then this is the sym edge. - * - * @return the next edge - */ - public HalfEdge next() - { - return next; - } - - /** - * Returns the edge previous to this one - * (with dest being the same as this orig). - * - * @return the previous edge to this one - */ - public HalfEdge prev() { - return sym.next().sym; - } - - public void setNext(HalfEdge e) - { - next = e; - } - - public HalfEdge oNext() { - return sym.next; - } - - /** - * Finds the edge starting at the origin of this edge - * with the given dest vertex, - * if any. - * - * @param dest the dest vertex to search for - * @return the edge with the required dest vertex, if it exists, - * or null - */ - public HalfEdge find(Coordinate dest) { - HalfEdge oNext = this; - do { - if (oNext == null) return null; - if (oNext.dest().equals2D(dest)) - return oNext; - oNext = oNext.oNext(); - } while (oNext != this); - return null; - } - - /** - * Tests whether this edge has the given orig and dest vertices. - * - * @param p0 the origin vertex to test - * @param p1 the destination vertex to test - * @return true if the vertices are equal to the ones of this edge - */ - public boolean equals(Coordinate p0, Coordinate p1) { - return orig.equals2D(p0) && sym.orig.equals(p1); - } - - /** - * Inserts an edge - * into the ring of edges around the origin vertex of this edge. - * The inserted edge must have the same origin as this edge. - * - * @param e the edge to insert - */ - public void insert(HalfEdge e) { - // if no other edge around origin - if (oNext() == this) { - // set linkage so ring is correct - insertAfter(e); - return; - } - - // otherwise, find edge to insert after - int ecmp = compareTo(e); - HalfEdge ePrev = this; - do { - HalfEdge oNext = ePrev.oNext(); - int cmp = oNext.compareTo(e); - if (cmp != ecmp || oNext == this) { - ePrev.insertAfter(e); - return; - } - ePrev = oNext; - } while (ePrev != this); - Assert.shouldNeverReachHere(); - } - - /** - * Insert an edge with the same origin after this one. - * Assumes that the inserted edge is in the correct - * position around the ring. - * - * @param e the edge to insert (with same origin) - */ - private void insertAfter(HalfEdge e) { - Assert.equals(orig, e.orig()); - HalfEdge save = oNext(); - sym.setNext(e); - e.sym().setNext(save); - } - - /** - * Compares edges which originate at the same vertex - * based on the angle they make at their origin vertex with the positive X-axis. - * This allows sorting edges around their origin vertex in CCW order. - */ - public int compareTo(Object obj) - { - HalfEdge e = (HalfEdge) obj; - int comp = compareAngularDirection(e); - return comp; - } - - /** - * Implements the total order relation: - *

          - * The angle of edge a is greater than the angle of edge b, - * where the angle of an edge is the angle made by - * the first segment of the edge with the positive x-axis - *

          - * When applied to a list of edges originating at the same point, - * this produces a CCW ordering of the edges around the point. - *

          - * Using the obvious algorithm of computing the angle is not robust, - * since the angle calculation is susceptible to roundoff error. - * A robust algorithm is: - *

            - *
          • First, compare the quadrants the edge vectors lie in. - * If the quadrants are different, - * it is trivial to determine which edge has a greater angle. - * - *
          • if the vectors lie in the same quadrant, the - * {@link CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate)} function - * can be used to determine the relative orientation of the vectors. - *
          - */ - public int compareAngularDirection(HalfEdge e) - { - double dx = deltaX(); - double dy = deltaY(); - double dx2 = e.deltaX(); - double dy2 = e.deltaY(); - - // same vector - if (dx == dx2 && dy == dy2) - return 0; - - double quadrant = Quadrant.quadrant(dx, dy); - double quadrant2 = Quadrant.quadrant(dx2, dy2); - - // if the vectors are in different quadrants, determining the ordering is trivial - if (quadrant > quadrant2) return 1; - if (quadrant < quadrant2) return -1; - // vectors are in the same quadrant - // Check relative orientation of direction vectors - // this is > e if it is CCW of e - return CGAlgorithms.computeOrientation(e.orig, e.dest(), dest()); - } - - /** - * The X component of the distance between the orig and dest vertices. - * - * @return the X component of the edge length - */ - public double deltaX() { return sym.orig.x - orig.x; } - - /** - * The Y component of the distance between the orig and dest vertices. - * - * @return the Y component of the edge length - */ - public double deltaY() { return sym.orig.y - orig.y; } - - /** - * Computes a string representation of a HalfEdge. - * - * @return a string representation - */ - public String toString() - { - return "HE("+orig.x + " " + orig.y - + ", " - + sym.orig.x + " " + sym.orig.y - + ")"; - } - - /** - * Computes the degree of the origin vertex. - * The degree is the number of edges - * originating from the vertex. - * - * @return the degree of the origin vertex - */ - public int degree() { - int degree = 0; - HalfEdge e = this; - do { - degree++; - e = e.oNext(); - } while (e != this); - return degree; - } - - /** - * Finds the first node previous to this edge, if any. - * If no such node exists (i.e the edge is part of a ring) - * then null is returned. - * - * @return an edge originating at the node prior to this edge, if any, - * or null if no node exists - */ - public HalfEdge prevNode() { - HalfEdge e = this; - while (e.degree() == 2) { - e = e.prev(); - if (e == this) - return null; - } - return e; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/edgegraph/MarkHalfEdge.java b/src/main/java/com/vividsolutions/jts/edgegraph/MarkHalfEdge.java deleted file mode 100644 index e6f06bbdc7..0000000000 --- a/src/main/java/com/vividsolutions/jts/edgegraph/MarkHalfEdge.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.vividsolutions.jts.edgegraph; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A {@link HalfEdge} which supports - * marking edges with a boolean flag. - * Useful for algorithms which perform graph traversals. - * - * @author Martin Davis - * - */ -public class MarkHalfEdge extends HalfEdge -{ - /** - * Tests whether the given edge is marked. - * - * @param e the edge to test - * @return true if the edge is marked - */ - public static boolean isMarked(HalfEdge e) - { - return ((MarkHalfEdge) e).isMarked(); - } - - /** - * Marks the given edge. - * - * @param e the edge to mark - */ - public static void mark(HalfEdge e) - { - ((MarkHalfEdge) e).mark(); - } - - /** - * Sets the mark for the given edge to a boolean value. - * - * @param e the edge to set - * @param isMarked the mark value - */ - public static void setMark(HalfEdge e, boolean isMarked) - { - ((MarkHalfEdge) e).setMark(isMarked); - } - - /** - * Sets the mark for the given edge pair to a boolean value. - * - * @param e an edge of the pair to update - * @param isMarked the mark value to set - */ - public static void setMarkBoth(HalfEdge e, boolean isMarked) - { - ((MarkHalfEdge) e).setMark(isMarked); - ((MarkHalfEdge) e.sym()).setMark(isMarked); - } - - /** - * Marks the edges in a pair. - * - * @param e an edge of the pair to mark - */ - public static void markBoth(HalfEdge e) { - ((MarkHalfEdge) e).mark(); - ((MarkHalfEdge) e.sym()).mark(); - } - - private boolean isMarked = false; - - /** - * Creates a new marked edge. - * - * @param orig the coordinate of the edge origin - */ - public MarkHalfEdge(Coordinate orig) { - super(orig); - } - - /** - * Tests whether this edge is marked. - * - * @return true if this edge is marked - */ - public boolean isMarked() - { - return isMarked ; - } - - /** - * Marks this edge. - * - */ - public void mark() - { - isMarked = true; - } - - /** - * Sets the value of the mark on this edge. - * - * @param isMarked the mark value to set - */ - public void setMark(boolean isMarked) - { - this.isMarked = isMarked; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/Coordinate.java b/src/main/java/com/vividsolutions/jts/geom/Coordinate.java deleted file mode 100644 index 0297b23152..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Coordinate.java +++ /dev/null @@ -1,445 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; -import java.util.Comparator; -import com.vividsolutions.jts.util.Assert; -import com.vividsolutions.jts.util.NumberUtil; - - -/** - * A lightweight class used to store coordinates - * on the 2-dimensional Cartesian plane. - * It is distinct from {@link Point}, which is a subclass of {@link Geometry}. - * Unlike objects of type {@link Point} (which contain additional - * information such as an envelope, a precision model, and spatial reference - * system information), a Coordinate only contains ordinate values - * and accessor methods.

          - * - * Coordinates are two-dimensional points, with an additional Z-ordinate. - * If an Z-ordinate value is not specified or not defined, - * constructed coordinates have a Z-ordinate of NaN - * (which is also the value of NULL_ORDINATE). - * The standard comparison functions ignore the Z-ordinate. - * Apart from the basic accessor functions, JTS supports - * only specific operations involving the Z-ordinate. - * - *@version 1.7 - */ -public class Coordinate implements Comparable, Cloneable, Serializable { - private static final long serialVersionUID = 6683108902428366910L; - - /** - * The value used to indicate a null or missing ordinate value. - * In particular, used for the value of ordinates for dimensions - * greater than the defined dimension of a coordinate. - */ - public static final double NULL_ORDINATE = Double.NaN; - - /** - * Standard ordinate index values - */ - public static final int X = 0; - public static final int Y = 1; - public static final int Z = 2; - - /** - * The x-coordinate. - */ - public double x; - /** - * The y-coordinate. - */ - public double y; - /** - * The z-coordinate. - */ - public double z; - - /** - * Constructs a Coordinate at (x,y,z). - * - *@param x the x-value - *@param y the y-value - *@param z the z-value - */ - public Coordinate(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * Constructs a Coordinate at (0,0,NaN). - */ - public Coordinate() { - this(0.0, 0.0); - } - - /** - * Constructs a Coordinate having the same (x,y,z) values as - * other. - * - *@param c the Coordinate to copy. - */ - public Coordinate(Coordinate c) { - this(c.x, c.y, c.z); - } - - /** - * Constructs a Coordinate at (x,y,NaN). - * - *@param x the x-value - *@param y the y-value - */ - public Coordinate(double x, double y) { - this(x, y, NULL_ORDINATE); - } - - /** - * Sets this Coordinates (x,y,z) values to that of other. - * - *@param other the Coordinate to copy - */ - public void setCoordinate(Coordinate other) { - x = other.x; - y = other.y; - z = other.z; - } - - /** - * Gets the ordinate value for the given index. - * The supported values for the index are - * {@link X}, {@link Y}, and {@link Z}. - * - * @param ordinateIndex the ordinate index - * @return the value of the ordinate - * @throws IllegalArgumentException if the index is not valid - */ - public double getOrdinate(int ordinateIndex) - { - switch (ordinateIndex) { - case X: return x; - case Y: return y; - case Z: return z; - } - throw new IllegalArgumentException("Invalid ordinate index: " + ordinateIndex); - } - - /** - * Sets the ordinate for the given index - * to a given value. - * The supported values for the index are - * {@link X}, {@link Y}, and {@link Z}. - * - * @param ordinateIndex the ordinate index - * @param value the value to set - * @throws IllegalArgumentException if the index is not valid - */ - public void setOrdinate(int ordinateIndex, double value) - { - switch (ordinateIndex) { - case X: - x = value; - break; - case Y: - y = value; - break; - case Z: - z = value; - break; - default: - throw new IllegalArgumentException("Invalid ordinate index: " + ordinateIndex); - } - } - - /** - * Returns whether the planar projections of the two Coordinates - * are equal. - * - *@param other a Coordinate with which to do the 2D comparison. - *@return true if the x- and y-coordinates are equal; the - * z-coordinates do not have to be equal. - */ - public boolean equals2D(Coordinate other) { - if (x != other.x) { - return false; - } - if (y != other.y) { - return false; - } - return true; - } - - /** - * Tests if another coordinate has the same values for the X and Y ordinates. - * The Z ordinate is ignored. - * - *@param other a Coordinate with which to do the 2D comparison. - *@return true if other is a Coordinate - * with the same values for X and Y. - */ - public boolean equals2D(Coordinate c, double tolerance){ - if (! NumberUtil.equalsWithTolerance(this.x, c.x, tolerance)) { - return false; - } - if (! NumberUtil.equalsWithTolerance(this.y, c.y, tolerance)) { - return false; - } - return true; - } - - /** - * Tests if another coordinate has the same values for the X, Y and Z ordinates. - * - *@param other a Coordinate with which to do the 3D comparison. - *@return true if other is a Coordinate - * with the same values for X, Y and Z. - */ - public boolean equals3D(Coordinate other) { - return (x == other.x) && (y == other.y) && - ((z == other.z) || - (Double.isNaN(z) && Double.isNaN(other.z))); - } - - /** - * Tests if another coordinate has the same value for Z, within a tolerance. - * - * @param c a coordinate - * @param tolerance the tolerance value - * @return true if the Z ordinates are within the given tolerance - */ - public boolean equalInZ(Coordinate c, double tolerance){ - return NumberUtil.equalsWithTolerance(this.z, c.z, tolerance); - } - - /** - * Returns true if other has the same values for - * the x and y ordinates. - * Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. - * - *@param other a Coordinate with which to do the comparison. - *@return true if other is a Coordinate - * with the same values for the x and y ordinates. - */ - public boolean equals(Object other) { - if (!(other instanceof Coordinate)) { - return false; - } - return equals2D((Coordinate) other); - } - - /** - * Compares this {@link Coordinate} with the specified {@link Coordinate} for order. - * This method ignores the z value when making the comparison. - * Returns: - *

            - *
          • -1 : this.x < other.x || ((this.x == other.x) && (this.y < - * other.y)) - *
          • 0 : this.x == other.x && this.y = other.y - *
          • 1 : this.x > other.x || ((this.x == other.x) && (this.y > other.y)) - * - *
          - * Note: This method assumes that ordinate values - * are valid numbers. NaN values are not handled correctly. - * - *@param o the Coordinate with which this Coordinate - * is being compared - *@return -1, zero, or 1 as this Coordinate - * is less than, equal to, or greater than the specified Coordinate - */ - public int compareTo(Object o) { - Coordinate other = (Coordinate) o; - - if (x < other.x) return -1; - if (x > other.x) return 1; - if (y < other.y) return -1; - if (y > other.y) return 1; - return 0; - } - - /** - * Returns a String of the form (x,y,z) . - * - *@return a String of the form (x,y,z) - */ - public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; - } - - public Object clone() { - try { - Coordinate coord = (Coordinate) super.clone(); - - return coord; // return the clone - } catch (CloneNotSupportedException e) { - Assert.shouldNeverReachHere( - "this shouldn't happen because this class is Cloneable"); - - return null; - } - } - - /** - * Computes the 2-dimensional Euclidean distance to another location. - * The Z-ordinate is ignored. - * - * @param c a point - * @return the 2-dimensional Euclidean distance between the locations - */ - public double distance(Coordinate c) { - double dx = x - c.x; - double dy = y - c.y; - return Math.sqrt(dx * dx + dy * dy); - } - - /** - * Computes the 3-dimensional Euclidean distance to another location. - * - * @param c a coordinate - * @return the 3-dimensional Euclidean distance between the locations - */ - public double distance3D(Coordinate c) { - double dx = x - c.x; - double dy = y - c.y; - double dz = z - c.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - /** - * Gets a hashcode for this coordinate. - * - * @return a hashcode for this coordinate - */ - public int hashCode() { - //Algorithm from Effective Java by Joshua Bloch [Jon Aquino] - int result = 17; - result = 37 * result + hashCode(x); - result = 37 * result + hashCode(y); - return result; - } - - /** - * Computes a hash code for a double value, using the algorithm from - * Joshua Bloch's book Effective Java" - * - * @return a hashcode for the double value - */ - public static int hashCode(double x) { - long f = Double.doubleToLongBits(x); - return (int)(f^(f>>>32)); - } - - - /** - * Compares two {@link Coordinate}s, allowing for either a 2-dimensional - * or 3-dimensional comparison, and handling NaN values correctly. - */ - public static class DimensionalComparator - implements Comparator - { - /** - * Compare two doubles, allowing for NaN values. - * NaN is treated as being less than any valid number. - * - * @param a a double - * @param b a double - * @return -1, 0, or 1 depending on whether a is less than, equal to or greater than b - */ - public static int compare(double a, double b) - { - if (a < b) return -1; - if (a > b) return 1; - - if (Double.isNaN(a)) { - if (Double.isNaN(b)) return 0; - return -1; - } - - if (Double.isNaN(b)) return 1; - return 0; - } - - private int dimensionsToTest = 2; - - /** - * Creates a comparator for 2 dimensional coordinates. - */ - public DimensionalComparator() - { - this(2); - } - - /** - * Creates a comparator for 2 or 3 dimensional coordinates, depending - * on the value provided. - * - * @param dimensionsToTest the number of dimensions to test - */ - public DimensionalComparator(int dimensionsToTest) - { - if (dimensionsToTest != 2 && dimensionsToTest != 3) - throw new IllegalArgumentException("only 2 or 3 dimensions may be specified"); - this.dimensionsToTest = dimensionsToTest; - } - - /** - * Compares two {@link Coordinate}s along to the number of - * dimensions specified. - * - * @param o1 a {@link Coordinate} - * @param o2 a {link Coordinate} - * @return -1, 0, or 1 depending on whether o1 is less than, - * equal to, or greater than 02 - * - */ - public int compare(Object o1, Object o2) - { - Coordinate c1 = (Coordinate) o1; - Coordinate c2 = (Coordinate) o2; - - int compX = compare(c1.x, c2.x); - if (compX != 0) return compX; - - int compY = compare(c1.y, c2.y); - if (compY != 0) return compY; - - if (dimensionsToTest <= 2) return 0; - - int compZ = compare(c1.z, c2.z); - return compZ; - } - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateArrays.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateArrays.java deleted file mode 100644 index dba958b291..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateArrays.java +++ /dev/null @@ -1,489 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.*; - -import com.vividsolutions.jts.math.MathUtil; - -/** - * Useful utility functions for handling Coordinate arrays - * - * @version 1.7 - */ -public class CoordinateArrays { - - private final static Coordinate[] coordArrayType = new Coordinate[0]; - - /** - * Tests whether an array of {@link Coordinate}s forms a ring, - * by checking length and closure. - * Self-intersection is not checked. - * - * @param pts an array of Coordinates - * @return true if the coordinate form a ring. - */ - public static boolean isRing(Coordinate[] pts) - { - if (pts.length < 4) return false; - if (! pts[0].equals2D(pts[pts.length -1])) return false; - return true; - } - - /** - * Finds a point in a list of points which is not contained in another list of points - * @param testPts the {@link Coordinate}s to test - * @param pts an array of {@link Coordinate}s to test the input points against - * @return a {@link Coordinate} from testPts which is not in pts, ' - * or null - */ - public static Coordinate ptNotInList(Coordinate[] testPts, Coordinate[] pts) - { - for (int i = 0; i < testPts.length; i++) { - Coordinate testPt = testPts[i]; - if (CoordinateArrays.indexOf(testPt, pts) < 0) - return testPt; - } - return null; - } - - /** - * Compares two {@link Coordinate} arrays - * in the forward direction of their coordinates, - * using lexicographic ordering. - * - * @param pts1 - * @param pts2 - * @return an integer indicating the order - */ - public static int compare(Coordinate[] pts1, Coordinate[] pts2) { - int i = 0; - while (i < pts1.length && i < pts2.length) { - int compare = pts1[i].compareTo(pts2[i]); - if (compare != 0) - return compare; - i++; - } - // handle situation when arrays are of different length - if (i < pts2.length) return -1; - if (i < pts1.length) return 1; - - return 0; - } - - /** - * A {@link Comparator} for {@link Coordinate} arrays - * in the forward direction of their coordinates, - * using lexicographic ordering. - */ - public static class ForwardComparator - implements Comparator - { - public int compare(Object o1, Object o2) { - Coordinate[] pts1 = (Coordinate[]) o1; - Coordinate[] pts2 = (Coordinate[]) o2; - - return CoordinateArrays.compare(pts1, pts2); - } - } - - - /** - * Determines which orientation of the {@link Coordinate} array - * is (overall) increasing. - * In other words, determines which end of the array is "smaller" - * (using the standard ordering on {@link Coordinate}). - * Returns an integer indicating the increasing direction. - * If the sequence is a palindrome, it is defined to be - * oriented in a positive direction. - * - * @param pts the array of Coordinates to test - * @return 1 if the array is smaller at the start - * or is a palindrome, - * -1 if smaller at the end - */ - public static int increasingDirection(Coordinate[] pts) { - for (int i = 0; i < pts.length / 2; i++) { - int j = pts.length - 1 - i; - // skip equal points on both ends - int comp = pts[i].compareTo(pts[j]); - if (comp != 0) - return comp; - } - // array must be a palindrome - defined to be in positive direction - return 1; - } - - /** - * Determines whether two {@link Coordinate} arrays of equal length - * are equal in opposite directions. - * - * @param pts1 - * @param pts2 - * @return true if the two arrays are equal in opposite directions. - */ - private static boolean isEqualReversed(Coordinate[] pts1, Coordinate[] pts2) - { - for (int i = 0; i < pts1.length; i++) { - Coordinate p1 = pts1[i]; - Coordinate p2 = pts2[pts1.length - i - 1]; - if (p1.compareTo(p2) != 0) - return false; - } - return true; - } - - /** - * A {@link Comparator} for {@link Coordinate} arrays - * modulo their directionality. - * E.g. if two coordinate arrays are identical but reversed - * they will compare as equal under this ordering. - * If the arrays are not equal, the ordering returned - * is the ordering in the forward direction. - * - */ - public static class BidirectionalComparator - implements Comparator - { - public int compare(Object o1, Object o2) { - Coordinate[] pts1 = (Coordinate[]) o1; - Coordinate[] pts2 = (Coordinate[]) o2; - - if (pts1.length < pts2.length) return -1; - if (pts1.length > pts2.length) return 1; - - if (pts1.length == 0) return 0; - - int forwardComp = CoordinateArrays.compare(pts1, pts2); - boolean isEqualRev = isEqualReversed(pts1, pts2); - if (isEqualRev) - return 0; - return forwardComp; - } - - public int OLDcompare(Object o1, Object o2) { - Coordinate[] pts1 = (Coordinate[]) o1; - Coordinate[] pts2 = (Coordinate[]) o2; - - if (pts1.length < pts2.length) return -1; - if (pts1.length > pts2.length) return 1; - - if (pts1.length == 0) return 0; - - int dir1 = increasingDirection(pts1); - int dir2 = increasingDirection(pts2); - - int i1 = dir1 > 0 ? 0 : pts1.length - 1; - int i2 = dir2 > 0 ? 0 : pts1.length - 1; - - for (int i = 0; i < pts1.length; i++) { - int comparePt = pts1[i1].compareTo(pts2[i2]); - if (comparePt != 0) - return comparePt; - i1 += dir1; - i2 += dir2; - } - return 0; - } - - } - - /** - * Creates a deep copy of the argument {@link Coordinate} array. - * - * @param coordinates an array of Coordinates - * @return a deep copy of the input - */ - public static Coordinate[] copyDeep(Coordinate[] coordinates) { - Coordinate[] copy = new Coordinate[coordinates.length]; - for (int i = 0; i < coordinates.length; i++) { - copy[i] = new Coordinate(coordinates[i]); - } - return copy; - } - - /** - * Creates a deep copy of a given section of a source {@link Coordinate} array - * into a destination Coordinate array. - * The destination array must be an appropriate size to receive - * the copied coordinates. - * - * @param src an array of Coordinates - * @param srcStart the index to start copying from - * @param dest the - * @param destStart the destination index to start copying to - * @param length the number of items to copy - */ - public static void copyDeep(Coordinate[] src, int srcStart, Coordinate[] dest, int destStart, int length) { - for (int i = 0; i < length; i++) { - dest[destStart + i] = new Coordinate(src[srcStart + i]); - } - } - - /** - * Converts the given Collection of Coordinates into a Coordinate array. - */ - public static Coordinate[] toCoordinateArray(Collection coordList) - { - return (Coordinate[]) coordList.toArray(coordArrayType); - } - - /** - * Returns whether #equals returns true for any two consecutive Coordinates - * in the given array. - */ - public static boolean hasRepeatedPoints(Coordinate[] coord) - { - for (int i = 1; i < coord.length; i++) { - if (coord[i - 1].equals(coord[i]) ) { - return true; - } - } - return false; - } - - /** - * Returns either the given coordinate array if its length is greater than the - * given amount, or an empty coordinate array. - */ - public static Coordinate[] atLeastNCoordinatesOrNothing(int n, Coordinate[] c) { - return c.length >= n ? c : new Coordinate[] { }; - } - - /** - * If the coordinate array argument has repeated points, - * constructs a new array containing no repeated points. - * Otherwise, returns the argument. - * @see #hasRepeatedPoints(Coordinate[]) - */ - public static Coordinate[] removeRepeatedPoints(Coordinate[] coord) - { - if (! hasRepeatedPoints(coord)) return coord; - CoordinateList coordList = new CoordinateList(coord, false); - return coordList.toCoordinateArray(); - } - - /** - * Collapses a coordinate array to remove all null elements. - * - * @param coord the coordinate array to collapse - * @return an array containing only non-null elements - */ - public static Coordinate[] removeNull(Coordinate[] coord) - { - int nonNull = 0; - for (int i = 0; i < coord.length; i++) { - if (coord[i] != null) nonNull++; - } - Coordinate[] newCoord = new Coordinate[nonNull]; - // empty case - if (nonNull == 0) return newCoord; - - int j = 0; - for (int i = 0; i < coord.length; i++) { - if (coord[i] != null) newCoord[j++] = coord[i]; - } - return newCoord; - } - - /** - * Reverses the coordinates in an array in-place. - */ - public static void reverse(Coordinate[] coord) - { - int last = coord.length - 1; - int mid = last / 2; - for (int i = 0; i <= mid; i++) { - Coordinate tmp = coord[i]; - coord[i] = coord[last - i]; - coord[last - i] = tmp; - } - } - - /** - * Returns true if the two arrays are identical, both null, or pointwise - * equal (as compared using Coordinate#equals) - * @see Coordinate#equals(Object) - */ - public static boolean equals( - Coordinate[] coord1, - Coordinate[] coord2) - { - if (coord1 == coord2) return true; - if (coord1 == null || coord2 == null) return false; - if (coord1.length != coord2.length) return false; - for (int i = 0; i < coord1.length; i++) { - if (! coord1[i].equals(coord2[i])) return false; - } - return true; - } - - /** - * Returns true if the two arrays are identical, both null, or pointwise - * equal, using a user-defined {@link Comparator} for {@link Coordinate} s - * - * @param coord1 an array of Coordinates - * @param coord2 an array of Coordinates - * @param coordinateComparator a Comparator for Coordinates - */ - public static boolean equals( - Coordinate[] coord1, - Coordinate[] coord2, - Comparator coordinateComparator) - { - if (coord1 == coord2) return true; - if (coord1 == null || coord2 == null) return false; - if (coord1.length != coord2.length) return false; - for (int i = 0; i < coord1.length; i++) { - if (coordinateComparator.compare(coord1[i], coord2[i]) != 0) - return false; - } - return true; - } - - /** - * Returns the minimum coordinate, using the usual lexicographic comparison. - * - *@param coordinates the array to search - *@return the minimum coordinate in the array, found using compareTo - *@see Coordinate#compareTo(Object) - */ - public static Coordinate minCoordinate(Coordinate[] coordinates) - { - Coordinate minCoord = null; - for (int i = 0; i < coordinates.length; i++) { - if (minCoord == null || minCoord.compareTo(coordinates[i]) > 0) { - minCoord = coordinates[i]; - } - } - return minCoord; - } - /** - * Shifts the positions of the coordinates until firstCoordinate - * is first. - * - *@param coordinates the array to rearrange - *@param firstCoordinate the coordinate to make first - */ - public static void scroll(Coordinate[] coordinates, Coordinate firstCoordinate) { - int i = indexOf(firstCoordinate, coordinates); - if (i < 0) return; - Coordinate[] newCoordinates = new Coordinate[coordinates.length]; - System.arraycopy(coordinates, i, newCoordinates, 0, coordinates.length - i); - System.arraycopy(coordinates, 0, newCoordinates, coordinates.length - i, i); - System.arraycopy(newCoordinates, 0, coordinates, 0, coordinates.length); - } - - /** - * Returns the index of coordinate in coordinates. - * The first position is 0; the second, 1; etc. - * - *@param coordinate the Coordinate to search for - *@param coordinates the array to search - *@return the position of coordinate, or -1 if it is - * not found - */ - public static int indexOf(Coordinate coordinate, Coordinate[] coordinates) { - for (int i = 0; i < coordinates.length; i++) { - if (coordinate.equals(coordinates[i])) { - return i; - } - } - return -1; - } - - /** - * Extracts a subsequence of the input {@link Coordinate} array - * from indices start to - * end (inclusive). - * The input indices are clamped to the array size; - * If the end index is less than the start index, - * the extracted array will be empty. - * - * @param pts the input array - * @param start the index of the start of the subsequence to extract - * @param end the index of the end of the subsequence to extract - * @return a subsequence of the input array - */ - public static Coordinate[] extract(Coordinate[] pts, int start, int end) - { - start = MathUtil.clamp(start, 0, pts.length); - end = MathUtil.clamp(end, -1, pts.length); - - int npts = end - start + 1; - if (end < 0) npts = 0; - if (start >= pts.length) npts = 0; - if (end < start) npts = 0; - - Coordinate[] extractPts = new Coordinate[npts]; - if (npts == 0) return extractPts; - - int iPts = 0; - for (int i = start; i <= end; i++) { - extractPts[iPts++] = pts[i]; - } - return extractPts; - } - - /** - * Computes the envelope of the coordinates. - * - * @param coordinates the coordinates to scan - * @return the envelope of the coordinates - */ - public static Envelope envelope(Coordinate[] coordinates) { - Envelope env = new Envelope(); - for (int i = 0; i < coordinates.length; i++) { - env.expandToInclude(coordinates[i]); - } - return env; - } - - /** - * Extracts the coordinates which intersect an {@link Envelope}. - * - * @param coordinates the coordinates to scan - * @param env the envelope to intersect with - * @return an array of the coordinates which intersect the envelope - */ - public static Coordinate[] intersection(Coordinate[] coordinates, Envelope env) { - CoordinateList coordList = new CoordinateList(); - for (int i = 0; i < coordinates.length; i++) { - if (env.intersects(coordinates[i])) - coordList.add(coordinates[i], true); - } - return coordList.toCoordinateArray(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateFilter.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateFilter.java deleted file mode 100644 index 2706ffee31..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateFilter.java +++ /dev/null @@ -1,66 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - - -/** - * An interface for classes which use the values of the coordinates in a {@link Geometry}. - * Coordinate filters can be used to implement centroid and - * envelope computation, and many other functions. - *

          - * CoordinateFilter is - * an example of the Gang-of-Four Visitor pattern. - *

          - * Note: it is not recommended to use these filters to mutate the coordinates. - * There is no guarantee that the coordinate is the actual object stored in the geometry. - * In particular, modified values may not be preserved if the target Geometry uses a non-default {@link CoordinateSequence}. - * If in-place mutation is required, use {@link CoordinateSequenceFilter}. - * - * @see Geometry#apply(CoordinateFilter) - * @see CoordinateSequenceFilter - * - *@version 1.7 - */ -public interface CoordinateFilter { - - /** - * Performs an operation with the coord. - * There is no guarantee that the coordinate is the actual object stored in the target geometry. - * - *@param coord a Coordinate to which the filter is applied. - */ - void filter(Coordinate coord); -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateList.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateList.java deleted file mode 100644 index 8aea63e38c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateList.java +++ /dev/null @@ -1,246 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; - -/** - * A list of {@link Coordinate}s, which may - * be set to prevent repeated coordinates from occuring in the list. - * - * - * @version 1.7 - */ -public class CoordinateList - extends ArrayList -{ - //With contributions from Markus Schaber [schabios@logi-track.com] - //[Jon Aquino 2004-03-25] - private final static Coordinate[] coordArrayType = new Coordinate[0]; - - /** - * Constructs a new list without any coordinates - */ - public CoordinateList() - { super(); - } - - /** - * Constructs a new list from an array of Coordinates, allowing repeated points. - * (I.e. this constructor produces a {@link CoordinateList} with exactly the same set of points - * as the input array.) - * - * @param coord the initial coordinates - */ - public CoordinateList(Coordinate[] coord) - { - ensureCapacity(coord.length); - add(coord, true); - } - - /** - * Constructs a new list from an array of Coordinates, - * allowing caller to specify if repeated points are to be removed. - * - * @param coord the array of coordinates to load into the list - * @param allowRepeated if false, repeated points are removed - */ - public CoordinateList(Coordinate[] coord, boolean allowRepeated) - { - ensureCapacity(coord.length); - add(coord, allowRepeated); - } - - public Coordinate getCoordinate(int i) { return (Coordinate) get(i); } - - - /** - * Adds a section of an array of coordinates to the list. - * @param coord The coordinates - * @param allowRepeated if set to false, repeated coordinates are collapsed - * @param start the index to start from - * @param end the index to add up to but not including - * @return true (as by general collection contract) - */ - public boolean add(Coordinate[] coord, boolean allowRepeated, int start, int end) - { - int inc = 1; - if (start > end) inc = -1; - - for (int i = start; i != end; i += inc) { - add(coord[i], allowRepeated); - } - return true; - } - - /** - * Adds an array of coordinates to the list. - * @param coord The coordinates - * @param allowRepeated if set to false, repeated coordinates are collapsed - * @param direction if false, the array is added in reverse order - * @return true (as by general collection contract) - */ - public boolean add(Coordinate[] coord, boolean allowRepeated, boolean direction) - { - if (direction) { - for (int i = 0; i < coord.length; i++) { - add(coord[i], allowRepeated); - } - } - else { - for (int i = coord.length - 1; i >= 0; i--) { - add(coord[i], allowRepeated); - } - } - return true; - } - - - /** - * Adds an array of coordinates to the list. - * @param coord The coordinates - * @param allowRepeated if set to false, repeated coordinates are collapsed - * @return true (as by general collection contract) - */ - public boolean add(Coordinate[] coord, boolean allowRepeated) - { - add(coord, allowRepeated, true); - return true; - } - - /** - * Adds a coordinate to the list. - * @param obj The coordinate to add - * @param allowRepeated if set to false, repeated coordinates are collapsed - * @return true (as by general collection contract) - */ - public boolean add(Object obj, boolean allowRepeated) - { - add((Coordinate) obj, allowRepeated); - return true; - } - - /** - * Adds a coordinate to the end of the list. - * - * @param coord The coordinates - * @param allowRepeated if set to false, repeated coordinates are collapsed - */ - public void add(Coordinate coord, boolean allowRepeated) - { - // don't add duplicate coordinates - if (! allowRepeated) { - if (size() >= 1) { - Coordinate last = (Coordinate) get(size() - 1); - if (last.equals2D(coord)) return; - } - } - super.add(coord); - } - - /** - * Inserts the specified coordinate at the specified position in this list. - * - * @param i the position at which to insert - * @param coord the coordinate to insert - * @param allowRepeated if set to false, repeated coordinates are collapsed - */ - public void add(int i, Coordinate coord, boolean allowRepeated) - { - // don't add duplicate coordinates - if (! allowRepeated) { - int size = size(); - if (size > 0) { - if (i > 0) { - Coordinate prev = (Coordinate) get(i - 1); - if (prev.equals2D(coord)) return; - } - if (i < size) { - Coordinate next = (Coordinate) get(i); - if (next.equals2D(coord)) return; - } - } - } - super.add(i, coord); - } - - /** Add an array of coordinates - * @param coll The coordinates - * @param allowRepeated if set to false, repeated coordinates are collapsed - * @return true (as by general collection contract) - */ - public boolean addAll(Collection coll, boolean allowRepeated) - { - boolean isChanged = false; - for (Iterator i = coll.iterator(); i.hasNext(); ) { - add((Coordinate) i.next(), allowRepeated); - isChanged = true; - } - return isChanged; - } - - /** - * Ensure this coordList is a ring, by adding the start point if necessary - */ - public void closeRing() - { - if (size() > 0) - add(new Coordinate((Coordinate) get(0)), false); - } - - /** Returns the Coordinates in this collection. - * - * @return the coordinates - */ - public Coordinate[] toCoordinateArray() - { - return (Coordinate[]) toArray(coordArrayType); - } - - /** - * Returns a deep copy of this CoordinateList instance. - * - * @return a clone of this CoordinateList instance - */ - public Object clone() { - CoordinateList clone = (CoordinateList) super.clone(); - for (int i = 0; i < this.size(); i++) { - clone.add(i, ((Coordinate) this.get(i)).clone()); - } - return clone; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequence.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateSequence.java deleted file mode 100644 index f0a4f0fb48..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequence.java +++ /dev/null @@ -1,187 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * The internal representation of a list of coordinates inside a Geometry. - *

          - * This allows Geometries to store their - * points using something other than the JTS {@link Coordinate} class. - * For example, a storage-efficient implementation - * might store coordinate sequences as an array of x's - * and an array of y's. - * Or a custom coordinate class might support extra attributes like M-values. - *

          - * Implementing a custom coordinate storage structure - * requires implementing the {@link CoordinateSequence} and - * {@link CoordinateSequenceFactory} interfaces. - * To use the custom CoordinateSequence, create a - * new {@link GeometryFactory} parameterized by the CoordinateSequenceFactory - * The {@link GeometryFactory} can then be used to create new {@link Geometry}s. - * The new Geometries - * will use the custom CoordinateSequence implementation. - *

          - * For an example, see the code for - * {@link ExtendedCoordinateExample}. - * - * @see CoordinateArraySequenceFactory - * @see PackedCoordinateSequenceFactory - * @see ExtendedCoordinateExample - * - * @version 1.7 - */ -public interface CoordinateSequence - extends Cloneable -{ - /** - * Standard ordinate index values - */ - int X = 0; - int Y = 1; - int Z = 2; - int M = 3; - - /** - * Returns the dimension (number of ordinates in each coordinate) - * for this sequence. - * - * @return the dimension of the sequence. - */ - int getDimension(); - - /** - * Returns (possibly a copy of) the i'th coordinate in this sequence. - * Whether or not the Coordinate returned is the actual underlying - * Coordinate or merely a copy depends on the implementation. - *

          - * Note that in the future the semantics of this method may change - * to guarantee that the Coordinate returned is always a copy. - * Callers should not to assume that they can modify a CoordinateSequence by - * modifying the object returned by this method. - * - * @param i the index of the coordinate to retrieve - * @return the i'th coordinate in the sequence - */ - Coordinate getCoordinate(int i); - - /** - * Returns a copy of the i'th coordinate in this sequence. - * This method optimizes the situation where the caller is - * going to make a copy anyway - if the implementation - * has already created a new Coordinate object, no further copy is needed. - * - * @param i the index of the coordinate to retrieve - * @return a copy of the i'th coordinate in the sequence - */ - Coordinate getCoordinateCopy(int i); - - /** - * Copies the i'th coordinate in the sequence to the supplied - * {@link Coordinate}. Only the first two dimensions are copied. - * - * @param index the index of the coordinate to copy - * @param coord a {@link Coordinate} to receive the value - */ - void getCoordinate(int index, Coordinate coord); - - /** - * Returns ordinate X (0) of the specified coordinate. - * - * @param index - * @return the value of the X ordinate in the index'th coordinate - */ - double getX(int index); - - /** - * Returns ordinate Y (1) of the specified coordinate. - * - * @param index - * @return the value of the Y ordinate in the index'th coordinate - */ - double getY(int index); - - /** - * Returns the ordinate of a coordinate in this sequence. - * Ordinate indices 0 and 1 are assumed to be X and Y. - * Ordinates indices greater than 1 have user-defined semantics - * (for instance, they may contain other dimensions or measure values). - * - * @param index the coordinate index in the sequence - * @param ordinateIndex the ordinate index in the coordinate (in range [0, dimension-1]) - */ - double getOrdinate(int index, int ordinateIndex); - - /** - * Returns the number of coordinates in this sequence. - * @return the size of the sequence - */ - int size(); - - /** - * Sets the value for a given ordinate of a coordinate in this sequence. - * - * @param index the coordinate index in the sequence - * @param ordinateIndex the ordinate index in the coordinate (in range [0, dimension-1]) - * @param value the new ordinate value - */ - void setOrdinate(int index, int ordinateIndex, double value); - - /** - * Returns (possibly copies of) the Coordinates in this collection. - * Whether or not the Coordinates returned are the actual underlying - * Coordinates or merely copies depends on the implementation. Note that - * if this implementation does not store its data as an array of Coordinates, - * this method will incur a performance penalty because the array needs to - * be built from scratch. - * - * @return a array of coordinates containing the point values in this sequence - */ - Coordinate[] toCoordinateArray(); - - /** - * Expands the given {@link Envelope} to include the coordinates in the sequence. - * Allows implementing classes to optimize access to coordinate values. - * - * @param env the envelope to expand - * @return a ref to the expanded envelope - */ - Envelope expandEnvelope(Envelope env); - - /** - * Returns a deep copy of this collection. - * Called by Geometry#clone. - * - * @return a copy of the coordinate sequence containing copies of all points - */ - Object clone(); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceComparator.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceComparator.java deleted file mode 100644 index e78f52829c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceComparator.java +++ /dev/null @@ -1,163 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom; - -import java.util.Comparator; - -/** - * Compares two {@link CoordinateSequence}s. - * For sequences of the same dimension, the ordering is lexicographic. - * Otherwise, lower dimensions are sorted before higher. - * The dimensions compared can be limited; if this is done - * ordinate dimensions above the limit will not be compared. - *

          - * If different behaviour is required for comparing size, dimension, or - * coordinate values, any or all methods can be overridden. - * - */ -public class CoordinateSequenceComparator - implements Comparator -{ - /** - * Compare two doubles, allowing for NaN values. - * NaN is treated as being less than any valid number. - * - * @param a a double - * @param b a double - * @return -1, 0, or 1 depending on whether a is less than, equal to or greater than b - */ - public static int compare(double a, double b) - { - if (a < b) return -1; - if (a > b) return 1; - - if (Double.isNaN(a)) { - if (Double.isNaN(b)) return 0; - return -1; - } - - if (Double.isNaN(b)) return 1; - return 0; - } - - /** - * The number of dimensions to test - */ - protected int dimensionLimit; - - /** - * Creates a comparator which will test all dimensions. - */ - public CoordinateSequenceComparator() - { - dimensionLimit = Integer.MAX_VALUE; - } - - /** - * Creates a comparator which will test only the specified number of dimensions. - * - * @param dimensionLimit the number of dimensions to test - */ - public CoordinateSequenceComparator(int dimensionLimit) - { - this.dimensionLimit = dimensionLimit; - } - - /** - * Compares two {@link CoordinateSequence}s for relative order. - * - * @param o1 a {@link CoordinateSequence} - * @param o2 a {@link CoordinateSequence} - * @return -1, 0, or 1 depending on whether o1 is less than, equal to, or greater than o2 - */ - public int compare(Object o1, Object o2) - { - CoordinateSequence s1 = (CoordinateSequence) o1; - CoordinateSequence s2 = (CoordinateSequence) o2; - - int size1 = s1.size(); - int size2 = s2.size(); - - int dim1 = s1.getDimension(); - int dim2 = s2.getDimension(); - - int minDim = dim1; - if (dim2 < minDim) - minDim = dim2; - boolean dimLimited = false; - if (dimensionLimit <= minDim) { - minDim = dimensionLimit; - dimLimited = true; - } - - // lower dimension is less than higher - if (! dimLimited) { - if (dim1 < dim2) return -1; - if (dim1 > dim2) return 1; - } - - // lexicographic ordering of point sequences - int i = 0; - while (i < size1 && i < size2) { - int ptComp = compareCoordinate(s1, s2, i, minDim); - if (ptComp != 0) return ptComp; - i++; - } - if (i < size1) return 1; - if (i < size2) return -1; - - return 0; - } - - /** - * Compares the same coordinate of two {@link CoordinateSequence}s - * along the given number of dimensions. - * - * @param s1 a {@link CoordinateSequence} - * @param s2 a {@link CoordinateSequence} - * @param i the index of the coordinate to test - * @param dimension the number of dimensiosn to test - * @return -1, 0, or 1 depending on whether s1[i] is less than, equal to, or greater than s2[i] - */ - protected int compareCoordinate(CoordinateSequence s1, CoordinateSequence s2, int i, int dimension) - { - for (int d = 0; d < dimension; d++) { - double ord1 = s1.getOrdinate(i, d); - double ord2 = s2.getOrdinate(i, d); - int comp = compare(ord1, ord2); - if (comp != 0) return comp; - } - return 0; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java deleted file mode 100644 index be93710d08..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * A factory to create concrete instances of {@link CoordinateSequence}s. - * Used to configure {@link GeometryFactory}s - * to provide specific kinds of CoordinateSequences. - * - * @version 1.7 - */ -public interface CoordinateSequenceFactory -{ - - /** - * Returns a {@link CoordinateSequence} based on the given array. - * Whether the array is copied or simply referenced - * is implementation-dependent. - * This method must handle null arguments by creating an empty sequence. - * - * @param coordinates the coordinates - */ - CoordinateSequence create(Coordinate[] coordinates); - - /** - * Creates a {@link CoordinateSequence} which is a copy - * of the given {@link CoordinateSequence}. - * This method must handle null arguments by creating an empty sequence. - * - * @param coordSeq the coordinate sequence to copy - */ - CoordinateSequence create(CoordinateSequence coordSeq); - - /** - * Creates a {@link CoordinateSequence} of the specified size and dimension. - * For this to be useful, the {@link CoordinateSequence} implementation must - * be mutable. - *

          - * If the requested dimension is larger than the CoordinateSequence implementation - * can provide, then a sequence of maximum possible dimension should be created. - * An error should not be thrown. - * - * @param size the number of coordinates in the sequence - * @param dimension the dimension of the coordinates in the sequence (if user-specifiable, - * otherwise ignored) - */ - CoordinateSequence create(int size, int dimension); - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFilter.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFilter.java deleted file mode 100644 index ce98bd8e5a..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequenceFilter.java +++ /dev/null @@ -1,101 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - - -/** - * An interface for classes which process the coordinates in a {@link CoordinateSequence}. - * A filter can either record information about each coordinate, - * or change the value of the coordinate. - * Filters can be - * used to implement operations such as coordinate transformations, centroid and - * envelope computation, and many other functions. - * {@link Geometry} classes support the concept of applying a - * CoordinateSequenceFilter to each - * {@link CoordinateSequence}s they contain. - *

          - * For maximum efficiency, the execution of filters can be short-circuited by using the {@link #isDone} method. - *

          - * CoordinateSequenceFilter is - * an example of the Gang-of-Four Visitor pattern. - *

          - * Note: In general, it is preferable to treat Geometrys as immutable. - * Mutation should be performed by creating a new Geometry object (see {@link GeometryEditor} - * and {@link GeometryTransformer} for convenient ways to do this). - * An exception to this rule is when a new Geometry has been created via {@link Geometry#clone()}. - * In this case mutating the Geometry will not cause aliasing issues, - * and a filter is a convenient way to implement coordinate transformation. - * - * @see Geometry#apply(CoordinateFilter) - * @see GeometryTransformer - * @see GeometryEditor - * - *@see Geometry#apply(CoordinateSequenceFilter) - *@author Martin Davis - *@version 1.7 - */ -public interface CoordinateSequenceFilter -{ - /** - * Performs an operation on a coordinate in a {@link CoordinateSequence}. - * - *@param seq the CoordinateSequence to which the filter is applied - *@param i the index of the coordinate to apply the filter to - */ - void filter(CoordinateSequence seq, int i); - - /** - * Reports whether the application of this filter can be terminated. - * Once this method returns false, it should - * continue to return false on every subsequent call. - * - * @return true if the application of this filter can be terminated. - */ - boolean isDone(); - - /** - * Reports whether the execution of this filter - * has modified the coordinates of the geometry. - * If so, {@link Geometry#geometryChanged} will be executed - * after this filter has finished being executed. - *

          - * Most filters can simply return a constant value reflecting - * whether they are able to change the coordinates. - * - * @return true if this filter has changed the coordinates of the geometry - */ - boolean isGeometryChanged(); -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequences.java b/src/main/java/com/vividsolutions/jts/geom/CoordinateSequences.java deleted file mode 100644 index f59ff5d2d6..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/CoordinateSequences.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import com.vividsolutions.jts.util.StringUtil; - - -/** - * Utility functions for manipulating {@link CoordinateSequence}s - * - * @version 1.7 - */ -public class CoordinateSequences { - - /** - * Reverses the coordinates in a sequence in-place. - */ - public static void reverse(CoordinateSequence seq) - { - int last = seq.size() - 1; - int mid = last / 2; - for (int i = 0; i <= mid; i++) { - swap(seq, i, last - i); - } - } - - /** - * Swaps two coordinates in a sequence. - * - * @param seq the sequence to modify - * @param i the index of a coordinate to swap - * @param j the index of a coordinate to swap - */ - public static void swap(CoordinateSequence seq, int i, int j) - { - if (i == j) return; - for (int dim = 0; dim < seq.getDimension(); dim++) { - double tmp = seq.getOrdinate(i, dim); - seq.setOrdinate(i, dim, seq.getOrdinate(j, dim)); - seq.setOrdinate(j, dim, tmp); - } - } - - /** - * Copies a section of a {@link CoordinateSequence} to another {@link CoordinateSequence}. - * The sequences may have different dimensions; - * in this case only the common dimensions are copied. - * - * @param src the sequence to copy from - * @param srcPos the position in the source sequence to start copying at - * @param dest the sequence to copy to - * @param destPos the position in the destination sequence to copy to - * @param length the number of coordinates to copy - */ - public static void copy(CoordinateSequence src, int srcPos, CoordinateSequence dest, int destPos, int length) - { - for (int i = 0; i < length; i++) { - copyCoord(src, srcPos + i, dest, destPos + i); - } - } - - /** - * Copies a coordinate of a {@link CoordinateSequence} to another {@link CoordinateSequence}. - * The sequences may have different dimensions; - * in this case only the common dimensions are copied. - * - * @param src the sequence to copy from - * @param srcPos the source coordinate to copy - * @param dest the sequence to copy to - * @param destPos the destination coordinate to copy to - */ - public static void copyCoord(CoordinateSequence src, int srcPos, CoordinateSequence dest, int destPos) - { - int minDim = Math.min(src.getDimension(), dest.getDimension()); - for (int dim = 0; dim < minDim; dim++) { - dest.setOrdinate(destPos, dim, src.getOrdinate(srcPos, dim)); - } - } - - /** - * Tests whether a {@link CoordinateSequence} forms a valid {@link LinearRing}, - * by checking the sequence length and closure - * (whether the first and last points are identical in 2D). - * Self-intersection is not checked. - * - * @param seq the sequence to test - * @return true if the sequence is a ring - * @see LinearRing - */ - public static boolean isRing(CoordinateSequence seq) - { - int n = seq.size(); - if (n == 0) return true; - // too few points - if (n <= 3) - return false; - // test if closed - return seq.getOrdinate(0, CoordinateSequence.X) == seq.getOrdinate(n-1, CoordinateSequence.X) - && seq.getOrdinate(0, CoordinateSequence.Y) == seq.getOrdinate(n-1, CoordinateSequence.Y); - } - - /** - * Ensures that a CoordinateSequence forms a valid ring, - * returning a new closed sequence of the correct length if required. - * If the input sequence is already a valid ring, it is returned - * without modification. - * If the input sequence is too short or is not closed, - * it is extended with one or more copies of the start point. - * - * @param fact the CoordinateSequenceFactory to use to create the new sequence - * @param seq the sequence to test - * @return the original sequence, if it was a valid ring, or a new sequence which is valid. - */ - public static CoordinateSequence ensureValidRing(CoordinateSequenceFactory fact, CoordinateSequence seq) - { - int n = seq.size(); - // empty sequence is valid - if (n == 0) return seq; - // too short - make a new one - if (n <= 3) - return createClosedRing(fact, seq, 4); - - boolean isClosed = seq.getOrdinate(0, CoordinateSequence.X) == seq.getOrdinate(n-1, CoordinateSequence.X) - && seq.getOrdinate(0, CoordinateSequence.Y) == seq.getOrdinate(n-1, CoordinateSequence.Y); - if (isClosed) return seq; - // make a new closed ring - return createClosedRing(fact, seq, n+1); - } - - private static CoordinateSequence createClosedRing(CoordinateSequenceFactory fact, CoordinateSequence seq, int size) - { - CoordinateSequence newseq = fact.create(size, seq.getDimension()); - int n = seq.size(); - copy(seq, 0, newseq, 0, n); - // fill remaining coordinates with start point - for (int i = n; i < size; i++) - copy(seq, 0, newseq, i, 1); - return newseq; - } - - public static CoordinateSequence extend(CoordinateSequenceFactory fact, CoordinateSequence seq, int size) - { - CoordinateSequence newseq = fact.create(size, seq.getDimension()); - int n = seq.size(); - copy(seq, 0, newseq, 0, n); - // fill remaining coordinates with end point, if it exists - if (n > 0) { - for (int i = n; i < size; i++) - copy(seq, n-1, newseq, i, 1); - } - return newseq; - } - - /** - * Tests whether two {@link CoordinateSequence}s are equal. - * To be equal, the sequences must be the same length. - * They do not need to be of the same dimension, - * but the ordinate values for the smallest dimension of the two - * must be equal. - * Two NaN ordinates values are considered to be equal. - * - * @param cs1 a CoordinateSequence - * @param cs2 a CoordinateSequence - * @return true if the sequences are equal in the common dimensions - */ - public static boolean isEqual(CoordinateSequence cs1, CoordinateSequence cs2) { - int cs1Size = cs1.size(); - int cs2Size = cs2.size(); - if (cs1Size != cs2Size) return false; - int dim = Math.min(cs1.getDimension(), cs2.getDimension()); - for (int i = 0; i < cs1Size; i++) { - for (int d = 0; d < dim; d++) { - double v1 = cs1.getOrdinate(i, d); - double v2 = cs2.getOrdinate(i, d); - if (cs1.getOrdinate(i, d) == cs2.getOrdinate(i, d)) - continue; - // special check for NaNs - if (Double.isNaN(v1) && Double.isNaN(v2)) - continue; - return false; - } - } - return true; - } - - /** - * Creates a string representation of a {@link CoordinateSequence}. - * The format is: - *

          -   *   ( ord0,ord1.. ord0,ord1,...  ... )
          -   * 
          - * - * @param cs the sequence to output - * @return the string representation of the sequence - */ - public static String toString(CoordinateSequence cs) - { - int size = cs.size(); - if (size == 0) - return "()"; - int dim = cs.getDimension(); - StringBuffer buf = new StringBuffer(); - buf.append('('); - for (int i = 0; i < size; i++) { - if (i > 0) buf.append(" "); - for (int d = 0; d < dim; d++) { - if (d > 0) buf.append(","); - buf.append(StringUtil.toString(cs.getOrdinate(i, d))); - } - } - buf.append(')'); - return buf.toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java b/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java deleted file mode 100644 index 9faa258425..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java +++ /dev/null @@ -1,218 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; -import java.io.Serializable; - -/** - * The CoordinateSequence implementation that Geometries use by default. In - * this implementation, Coordinates returned by #toArray and #get are live -- - * parties that change them are actually changing the - * DefaultCoordinateSequence's underlying data. - * - * @version 1.7 - * - * @deprecated no longer used - */ -class DefaultCoordinateSequence - implements CoordinateSequence, Serializable -{ - //With contributions from Markus Schaber [schabios@logi-track.com] 2004-03-26 - private static final long serialVersionUID = -915438501601840650L; - private Coordinate[] coordinates; - - /** - * Constructs a DefaultCoordinateSequence based on the given array (the - * array is not copied). - * - * @param coordinates the coordinate array that will be referenced. - */ - public DefaultCoordinateSequence(Coordinate[] coordinates) { - if (Geometry.hasNullElements(coordinates)) { - throw new IllegalArgumentException("Null coordinate"); - } - this.coordinates = coordinates; - } - - /** - * Creates a new sequence based on a deep copy of the given {@link CoordinateSequence}. - * - * @param coordSeq the coordinate sequence that will be copied. - */ - public DefaultCoordinateSequence(CoordinateSequence coordSeq) { - coordinates = new Coordinate[coordSeq.size()]; - for (int i = 0; i < coordinates.length; i++) { - coordinates[i] = coordSeq.getCoordinateCopy(i); - } - } - - /** - * Constructs a sequence of a given size, populated - * with new {@link Coordinate}s. - * - * @param size the size of the sequence to create - */ - public DefaultCoordinateSequence(int size) { - coordinates = new Coordinate[size]; - for (int i = 0; i < size; i++) { - coordinates[i] = new Coordinate(); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getDimension() - */ - public int getDimension() { return 3; } - - /** - * Get the Coordinate with index i. - * - * @param i - * the index of the coordinate - * @return the requested Coordinate instance - */ - public Coordinate getCoordinate(int i) { - return coordinates[i]; - } - /** - * Get a copy of the Coordinate with index i. - * - * @param i the index of the coordinate - * @return a copy of the requested Coordinate - */ - public Coordinate getCoordinateCopy(int i) { - return new Coordinate(coordinates[i]); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int) - */ - public void getCoordinate(int index, Coordinate coord) { - coord.x = coordinates[index].x; - coord.y = coordinates[index].y; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int) - */ - public double getX(int index) { - return coordinates[index].x; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int) - */ - public double getY(int index) { - return coordinates[index].y; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int) - */ - public double getOrdinate(int index, int ordinateIndex) - { - switch (ordinateIndex) { - case CoordinateSequence.X: return coordinates[index].x; - case CoordinateSequence.Y: return coordinates[index].y; - case CoordinateSequence.Z: return coordinates[index].z; - } - return Double.NaN; - } - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int, int, double) - */ - public void setOrdinate(int index, int ordinateIndex, double value) - { - switch (ordinateIndex) { - case CoordinateSequence.X: coordinates[index].x = value; break; - case CoordinateSequence.Y: coordinates[index].y = value; break; - case CoordinateSequence.Z: coordinates[index].z = value; break; - } - } - /** - * Creates a deep copy of the Object - * - * @return The deep copy - */ - public Object clone() { - Coordinate[] cloneCoordinates = new Coordinate[size()]; - for (int i = 0; i < coordinates.length; i++) { - cloneCoordinates[i] = (Coordinate) coordinates[i].clone(); - } - return new DefaultCoordinateSequence(cloneCoordinates); - } - /** - * Returns the size of the coordinate sequence - * - * @return the number of coordinates - */ - public int size() { - return coordinates.length; - } - /** - * This method exposes the internal Array of Coordinate Objects - * - * @return the Coordinate[] array. - */ - public Coordinate[] toCoordinateArray() { - return coordinates; - } - - public Envelope expandEnvelope(Envelope env) - { - for (int i = 0; i < coordinates.length; i++ ) { - env.expandToInclude(coordinates[i]); - } - return env; - } - - /** - * Returns the string Representation of the coordinate array - * - * @return The string - */ - public String toString() { - if (coordinates.length > 0) { - StringBuffer strBuf = new StringBuffer(17 * coordinates.length); - strBuf.append('('); - strBuf.append(coordinates[0]); - for (int i = 1; i < coordinates.length; i++) { - strBuf.append(", "); - strBuf.append(coordinates[i]); - } - strBuf.append(')'); - return strBuf.toString(); - } else { - return "()"; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java b/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java deleted file mode 100644 index 46eb786700..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java +++ /dev/null @@ -1,93 +0,0 @@ - -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; - -/** - * Creates CoordinateSequences represented as an array of {@link Coordinate}s. - * - * @version 1.7 - * - * @deprecated no longer used - */ -public class DefaultCoordinateSequenceFactory - implements CoordinateSequenceFactory, Serializable -{ - private static final long serialVersionUID = -4099577099607551657L; - private static final DefaultCoordinateSequenceFactory instanceObject = new DefaultCoordinateSequenceFactory(); - - public DefaultCoordinateSequenceFactory() { - } - - private Object readResolve() { - // see http://www.javaworld.com/javaworld/javatips/jw-javatip122.html - return DefaultCoordinateSequenceFactory.instance(); - } - - /** - * Returns the singleton instance of DefaultCoordinateSequenceFactory - */ - public static DefaultCoordinateSequenceFactory instance() { - return instanceObject; - } - - - - /** - * Returns a DefaultCoordinateSequence based on the given array (the array is - * not copied). - * - * @param coordinates - * the coordinates, which may not be null nor contain null - * elements - */ - public CoordinateSequence create(Coordinate[] coordinates) { - return new DefaultCoordinateSequence(coordinates); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence) - */ - public CoordinateSequence create(CoordinateSequence coordSeq) { - return new DefaultCoordinateSequence(coordSeq); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int) - */ - public CoordinateSequence create(int size, int dimension) { - return new DefaultCoordinateSequence(size); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/Dimension.java b/src/main/java/com/vividsolutions/jts/geom/Dimension.java deleted file mode 100644 index 7c51238b08..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Dimension.java +++ /dev/null @@ -1,164 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Provides constants representing the dimensions of a point, a curve and a surface. - * Also provides constants representing the dimensions of the empty geometry and - * non-empty geometries, and the wildcard constant {@link #DONTCARE} meaning "any dimension". - * These constants are used as the entries in {@link IntersectionMatrix}s. - * - * @version 1.7 - */ -public class Dimension { - - /** - * Dimension value of a point (0). - */ - public final static int P = 0; - - /** - * Dimension value of a curve (1). - */ - public final static int L = 1; - - /** - * Dimension value of a surface (2). - */ - public final static int A = 2; - - /** - * Dimension value of the empty geometry (-1). - */ - public final static int FALSE = -1; - - /** - * Dimension value of non-empty geometries (= {P, L, A}). - */ - public final static int TRUE = -2; - - /** - * Dimension value for any dimension (= {FALSE, TRUE}). - */ - public final static int DONTCARE = -3; - - /** - * Symbol for the FALSE pattern matrix entry - */ - public final static char SYM_FALSE = 'F'; - - /** - * Symbol for the TRUE pattern matrix entry - */ - public final static char SYM_TRUE = 'T'; - - /** - * Symbol for the DONTCARE pattern matrix entry - */ - public final static char SYM_DONTCARE = '*'; - - /** - * Symbol for the P (dimension 0) pattern matrix entry - */ - public final static char SYM_P = '0'; - - /** - * Symbol for the L (dimension 1) pattern matrix entry - */ - public final static char SYM_L = '1'; - - /** - * Symbol for the A (dimension 2) pattern matrix entry - */ - public final static char SYM_A = '2'; - - /** - * Converts the dimension value to a dimension symbol, for example, TRUE => 'T' - * . - * - *@param dimensionValue a number that can be stored in the IntersectionMatrix - * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. - *@return a character for use in the string representation of - * an IntersectionMatrix. Possible values are {T, F, * , 0, 1, 2} - * . - */ - public static char toDimensionSymbol(int dimensionValue) { - switch (dimensionValue) { - case FALSE: - return SYM_FALSE; - case TRUE: - return SYM_TRUE; - case DONTCARE: - return SYM_DONTCARE; - case P: - return SYM_P; - case L: - return SYM_L; - case A: - return SYM_A; - } - throw new IllegalArgumentException("Unknown dimension value: " + dimensionValue); - } - - /** - * Converts the dimension symbol to a dimension value, for example, '*' => DONTCARE - * . - * - *@param dimensionSymbol a character for use in the string representation of - * an IntersectionMatrix. Possible values are {T, F, * , 0, 1, 2} - * . - *@return a number that can be stored in the IntersectionMatrix - * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. - */ - public static int toDimensionValue(char dimensionSymbol) { - switch (Character.toUpperCase(dimensionSymbol)) { - case SYM_FALSE: - return FALSE; - case SYM_TRUE: - return TRUE; - case SYM_DONTCARE: - return DONTCARE; - case SYM_P: - return P; - case SYM_L: - return L; - case SYM_A: - return A; - } - throw new IllegalArgumentException("Unknown dimension symbol: " + dimensionSymbol); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/geom/Envelope.java b/src/main/java/com/vividsolutions/jts/geom/Envelope.java deleted file mode 100644 index a3b27a86f6..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Envelope.java +++ /dev/null @@ -1,779 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; - -/** - * Defines a rectangular region of the 2D coordinate plane. - * It is often used to represent the bounding box of a {@link Geometry}, - * e.g. the minimum and maximum x and y values of the {@link Coordinate}s. - *

          - * Envelopes support infinite or half-infinite regions, by using the values of - * Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY. - * Envelope objects may have a null value. - *

          - * When Envelope objects are created or initialized, - * the supplies extent values are automatically sorted into the correct order. - * - *@version 1.7 - */ -public class Envelope - implements Comparable, Serializable -{ - private static final long serialVersionUID = 5873921885273102420L; - - public int hashCode() { - //Algorithm from Effective Java by Joshua Bloch [Jon Aquino] - int result = 17; - result = 37 * result + Coordinate.hashCode(minx); - result = 37 * result + Coordinate.hashCode(maxx); - result = 37 * result + Coordinate.hashCode(miny); - result = 37 * result + Coordinate.hashCode(maxy); - return result; - } - - /** - * Test the point q to see whether it intersects the Envelope defined by p1-p2 - * @param p1 one extremal point of the envelope - * @param p2 another extremal point of the envelope - * @param q the point to test for intersection - * @return true if q intersects the envelope p1-p2 - */ - public static boolean intersects(Coordinate p1, Coordinate p2, Coordinate q) - { - //OptimizeIt shows that Math#min and Math#max here are a bottleneck. - //Replace with direct comparisons. [Jon Aquino] - if (((q.x >= (p1.x < p2.x ? p1.x : p2.x)) && (q.x <= (p1.x > p2.x ? p1.x : p2.x))) && - ((q.y >= (p1.y < p2.y ? p1.y : p2.y)) && (q.y <= (p1.y > p2.y ? p1.y : p2.y)))) { - return true; - } - return false; - } - - /** - * Tests whether the envelope defined by p1-p2 - * and the envelope defined by q1-q2 - * intersect. - * - * @param p1 one extremal point of the envelope P - * @param p2 another extremal point of the envelope P - * @param q1 one extremal point of the envelope Q - * @param q2 another extremal point of the envelope Q - * @return true if Q intersects P - */ - public static boolean intersects(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) - { - double minq = Math.min(q1.x, q2.x); - double maxq = Math.max(q1.x, q2.x); - double minp = Math.min(p1.x, p2.x); - double maxp = Math.max(p1.x, p2.x); - - if( minp > maxq ) - return false; - if( maxp < minq ) - return false; - - minq = Math.min(q1.y, q2.y); - maxq = Math.max(q1.y, q2.y); - minp = Math.min(p1.y, p2.y); - maxp = Math.max(p1.y, p2.y); - - if( minp > maxq ) - return false; - if( maxp < minq ) - return false; - return true; - } - - /** - * the minimum x-coordinate - */ - private double minx; - - /** - * the maximum x-coordinate - */ - private double maxx; - - /** - * the minimum y-coordinate - */ - private double miny; - - /** - * the maximum y-coordinate - */ - private double maxy; - - /** - * Creates a null Envelope. - */ - public Envelope() { - init(); - } - - /** - * Creates an Envelope for a region defined by maximum and minimum values. - * - *@param x1 the first x-value - *@param x2 the second x-value - *@param y1 the first y-value - *@param y2 the second y-value - */ - public Envelope(double x1, double x2, double y1, double y2) - { - init(x1, x2, y1, y2); - } - - /** - * Creates an Envelope for a region defined by two Coordinates. - * - *@param p1 the first Coordinate - *@param p2 the second Coordinate - */ - public Envelope(Coordinate p1, Coordinate p2) - { - init(p1.x, p2.x, p1.y, p2.y); - } - - /** - * Creates an Envelope for a region defined by a single Coordinate. - * - *@param p the Coordinate - */ - public Envelope(Coordinate p) - { - init(p.x, p.x, p.y, p.y); - } - - /** - * Create an Envelope from an existing Envelope. - * - *@param env the Envelope to initialize from - */ - public Envelope(Envelope env) - { - init(env); - } - - /** - * Initialize to a null Envelope. - */ - public void init() - { - setToNull(); - } - - /** - * Initialize an Envelope for a region defined by maximum and minimum values. - * - *@param x1 the first x-value - *@param x2 the second x-value - *@param y1 the first y-value - *@param y2 the second y-value - */ - public void init(double x1, double x2, double y1, double y2) - { - if (x1 < x2) { - minx = x1; - maxx = x2; - } - else { - minx = x2; - maxx = x1; - } - if (y1 < y2) { - miny = y1; - maxy = y2; - } - else { - miny = y2; - maxy = y1; - } - } - - /** - * Initialize an Envelope to a region defined by two Coordinates. - * - *@param p1 the first Coordinate - *@param p2 the second Coordinate - */ - public void init(Coordinate p1, Coordinate p2) - { - init(p1.x, p2.x, p1.y, p2.y); - } - - /** - * Initialize an Envelope to a region defined by a single Coordinate. - * - *@param p the coordinate - */ - public void init(Coordinate p) - { - init(p.x, p.x, p.y, p.y); - } - - /** - * Initialize an Envelope from an existing Envelope. - * - *@param env the Envelope to initialize from - */ - public void init(Envelope env) - { - this.minx = env.minx; - this.maxx = env.maxx; - this.miny = env.miny; - this.maxy = env.maxy; - } - - - /** - * Makes this Envelope a "null" envelope, that is, the envelope - * of the empty geometry. - */ - public void setToNull() { - minx = 0; - maxx = -1; - miny = 0; - maxy = -1; - } - - /** - * Returns true if this Envelope is a "null" - * envelope. - * - *@return true if this Envelope is uninitialized - * or is the envelope of the empty geometry. - */ - public boolean isNull() { - return maxx < minx; - } - - /** - * Returns the difference between the maximum and minimum x values. - * - *@return max x - min x, or 0 if this is a null Envelope - */ - public double getWidth() { - if (isNull()) { - return 0; - } - return maxx - minx; - } - - /** - * Returns the difference between the maximum and minimum y values. - * - *@return max y - min y, or 0 if this is a null Envelope - */ - public double getHeight() { - if (isNull()) { - return 0; - } - return maxy - miny; - } - - /** - * Returns the Envelopes minimum x-value. min x > max x - * indicates that this is a null Envelope. - * - *@return the minimum x-coordinate - */ - public double getMinX() { - return minx; - } - - /** - * Returns the Envelopes maximum x-value. min x > max x - * indicates that this is a null Envelope. - * - *@return the maximum x-coordinate - */ - public double getMaxX() { - return maxx; - } - - /** - * Returns the Envelopes minimum y-value. min y > max y - * indicates that this is a null Envelope. - * - *@return the minimum y-coordinate - */ - public double getMinY() { - return miny; - } - - /** - * Returns the Envelopes maximum y-value. min y > max y - * indicates that this is a null Envelope. - * - *@return the maximum y-coordinate - */ - public double getMaxY() { - return maxy; - } - - /** - * Gets the area of this envelope. - * - * @return the area of the envelope - * @return 0.0 if the envelope is null - */ - public double getArea() - { - return getWidth() * getHeight(); - } - - /** - * Gets the minimum extent of this envelope across both dimensions. - * - * @return the minimum extent of this envelope - */ - public double minExtent() - { - if (isNull()) return 0.0; - double w = getWidth(); - double h = getHeight(); - if (w < h) return w; - return h; - } - - /** - * Gets the maximum extent of this envelope across both dimensions. - * - * @return the maximum extent of this envelope - */ - public double maxExtent() - { - if (isNull()) return 0.0; - double w = getWidth(); - double h = getHeight(); - if (w > h) return w; - return h; - } - - /** - * Enlarges this Envelope so that it contains - * the given {@link Coordinate}. - * Has no effect if the point is already on or within the envelope. - * - *@param p the Coordinate to expand to include - */ - public void expandToInclude(Coordinate p) - { - expandToInclude(p.x, p.y); - } - - /** - * Expands this envelope by a given distance in all directions. - * Both positive and negative distances are supported. - * - * @param distance the distance to expand the envelope - */ - public void expandBy(double distance) - { - expandBy(distance, distance); - } - - /** - * Expands this envelope by a given distance in all directions. - * Both positive and negative distances are supported. - * - * @param deltaX the distance to expand the envelope along the the X axis - * @param deltaY the distance to expand the envelope along the the Y axis - */ - public void expandBy(double deltaX, double deltaY) - { - if (isNull()) return; - - minx -= deltaX; - maxx += deltaX; - miny -= deltaY; - maxy += deltaY; - - // check for envelope disappearing - if (minx > maxx || miny > maxy) - setToNull(); - } - - /** - * Enlarges this Envelope so that it contains - * the given point. - * Has no effect if the point is already on or within the envelope. - * - *@param x the value to lower the minimum x to or to raise the maximum x to - *@param y the value to lower the minimum y to or to raise the maximum y to - */ - public void expandToInclude(double x, double y) { - if (isNull()) { - minx = x; - maxx = x; - miny = y; - maxy = y; - } - else { - if (x < minx) { - minx = x; - } - if (x > maxx) { - maxx = x; - } - if (y < miny) { - miny = y; - } - if (y > maxy) { - maxy = y; - } - } - } - - /** - * Enlarges this Envelope so that it contains - * the other Envelope. - * Has no effect if other is wholly on or - * within the envelope. - * - *@param other the Envelope to expand to include - */ - public void expandToInclude(Envelope other) { - if (other.isNull()) { - return; - } - if (isNull()) { - minx = other.getMinX(); - maxx = other.getMaxX(); - miny = other.getMinY(); - maxy = other.getMaxY(); - } - else { - if (other.minx < minx) { - minx = other.minx; - } - if (other.maxx > maxx) { - maxx = other.maxx; - } - if (other.miny < miny) { - miny = other.miny; - } - if (other.maxy > maxy) { - maxy = other.maxy; - } - } - } - - /** - * Translates this envelope by given amounts in the X and Y direction. - * - * @param transX the amount to translate along the X axis - * @param transY the amount to translate along the Y axis - */ - public void translate(double transX, double transY) { - if (isNull()) { - return; - } - init(getMinX() + transX, getMaxX() + transX, - getMinY() + transY, getMaxY() + transY); - } - - /** - * Computes the coordinate of the centre of this envelope (as long as it is non-null - * - * @return the centre coordinate of this envelope - * null if the envelope is null - */ - public Coordinate centre() { - if (isNull()) return null; - return new Coordinate( - (getMinX() + getMaxX()) / 2.0, - (getMinY() + getMaxY()) / 2.0); - } - - /** - * Computes the intersection of two {@link Envelope}s. - * - * @param env the envelope to intersect with - * @return a new Envelope representing the intersection of the envelopes (this will be - * the null envelope if either argument is null, or they do not intersect - */ - public Envelope intersection(Envelope env) - { - if (isNull() || env.isNull() || ! intersects(env)) return new Envelope(); - - double intMinX = minx > env.minx ? minx : env.minx; - double intMinY = miny > env.miny ? miny : env.miny; - double intMaxX = maxx < env.maxx ? maxx : env.maxx; - double intMaxY = maxy < env.maxy ? maxy : env.maxy; - return new Envelope(intMinX, intMaxX, intMinY, intMaxY); - } - - - - /** - * Check if the region defined by other - * overlaps (intersects) the region of this Envelope. - * - *@param other the Envelope which this Envelope is - * being checked for overlapping - *@return true if the Envelopes overlap - */ - public boolean intersects(Envelope other) { - if (isNull() || other.isNull()) { return false; } - return !(other.minx > maxx || - other.maxx < minx || - other.miny > maxy || - other.maxy < miny); - } - /** - * @deprecated Use #intersects instead. In the future, #overlaps may be - * changed to be a true overlap check; that is, whether the intersection is - * two-dimensional. - */ - public boolean overlaps(Envelope other) { - return intersects(other); - } - - /** - * Check if the point p - * overlaps (lies inside) the region of this Envelope. - * - *@param p the Coordinate to be tested - *@return true if the point overlaps this Envelope - */ - public boolean intersects(Coordinate p) { - return intersects(p.x, p.y); - } - /** - * @deprecated Use #intersects instead. - */ - public boolean overlaps(Coordinate p) { - return intersects(p); - } - /** - * Check if the point (x, y) - * overlaps (lies inside) the region of this Envelope. - * - *@param x the x-ordinate of the point - *@param y the y-ordinate of the point - *@return true if the point overlaps this Envelope - */ - public boolean intersects(double x, double y) { - if (isNull()) return false; - return ! (x > maxx || - x < minx || - y > maxy || - y < miny); - } - /** - * @deprecated Use #intersects instead. - */ - public boolean overlaps(double x, double y) { - return intersects(x, y); - } - - /** - * Tests if the Envelope other - * lies wholely inside this Envelope (inclusive of the boundary). - *

          - * Note that this is not the same definition as the SFS contains, - * which would exclude the envelope boundary. - * - *@param other the Envelope to check - *@return true if other is contained in this Envelope - * - *@see #covers(Envelope) - */ - public boolean contains(Envelope other) { - return covers(other); - } - - /** - * Tests if the given point lies in or on the envelope. - *

          - * Note that this is not the same definition as the SFS contains, - * which would exclude the envelope boundary. - * - *@param p the point which this Envelope is - * being checked for containing - *@return true if the point lies in the interior or - * on the boundary of this Envelope. - * - *@see #covers(Coordinate) - */ - public boolean contains(Coordinate p) { - return covers(p); - } - - /** - * Tests if the given point lies in or on the envelope. - *

          - * Note that this is not the same definition as the SFS contains, - * which would exclude the envelope boundary. - * - *@param x the x-coordinate of the point which this Envelope is - * being checked for containing - *@param y the y-coordinate of the point which this Envelope is - * being checked for containing - *@return true if (x, y) lies in the interior or - * on the boundary of this Envelope. - * - *@see #covers(double, double) - */ - public boolean contains(double x, double y) { - return covers(x, y); - } - - /** - * Tests if the given point lies in or on the envelope. - * - *@param x the x-coordinate of the point which this Envelope is - * being checked for containing - *@param y the y-coordinate of the point which this Envelope is - * being checked for containing - *@return true if (x, y) lies in the interior or - * on the boundary of this Envelope. - */ - public boolean covers(double x, double y) { - if (isNull()) return false; - return x >= minx && - x <= maxx && - y >= miny && - y <= maxy; - } - - /** - * Tests if the given point lies in or on the envelope. - * - *@param p the point which this Envelope is - * being checked for containing - *@return true if the point lies in the interior or - * on the boundary of this Envelope. - */ - public boolean covers(Coordinate p) { - return covers(p.x, p.y); - } - - /** - * Tests if the Envelope other - * lies wholely inside this Envelope (inclusive of the boundary). - * - *@param other the Envelope to check - *@return true if this Envelope covers the other - */ - public boolean covers(Envelope other) { - if (isNull() || other.isNull()) { return false; } - return other.getMinX() >= minx && - other.getMaxX() <= maxx && - other.getMinY() >= miny && - other.getMaxY() <= maxy; - } - - /** - * Computes the distance between this and another - * Envelope. - * The distance between overlapping Envelopes is 0. Otherwise, the - * distance is the Euclidean distance between the closest points. - */ - public double distance(Envelope env) - { - if (intersects(env)) return 0; - - double dx = 0.0; - if (maxx < env.minx) - dx = env.minx - maxx; - else if (minx > env.maxx) - dx = minx - env.maxx; - - double dy = 0.0; - if (maxy < env.miny) - dy = env.miny - maxy; - else if (miny > env.maxy) dy = miny - env.maxy; - - // if either is zero, the envelopes overlap either vertically or horizontally - if (dx == 0.0) return dy; - if (dy == 0.0) return dx; - return Math.sqrt(dx * dx + dy * dy); - } - - public boolean equals(Object other) { - if (!(other instanceof Envelope)) { - return false; - } - Envelope otherEnvelope = (Envelope) other; - if (isNull()) { - return otherEnvelope.isNull(); - } - return maxx == otherEnvelope.getMaxX() && - maxy == otherEnvelope.getMaxY() && - minx == otherEnvelope.getMinX() && - miny == otherEnvelope.getMinY(); - } - - public String toString() - { - return "Env[" + minx + " : " + maxx + ", " + miny + " : " + maxy + "]"; - } - - /** - * Compares two envelopes using lexicographic ordering. - * The ordering comparison is based on the usual numerical - * comparison between the sequence of ordinates. - * Null envelopes are less than all non-null envelopes. - * - * @param o an Envelope object - */ - public int compareTo(Object o) { - Envelope env = (Envelope) o; - // compare nulls if present - if (isNull()) { - if (env.isNull()) return 0; - return -1; - } - else { - if (env.isNull()) return 1; - } - // compare based on numerical ordering of ordinates - if (minx < env.minx) return -1; - if (minx > env.minx) return 1; - if (miny < env.miny) return -1; - if (miny > env.miny) return 1; - if (maxx < env.maxx) return -1; - if (maxx > env.maxx) return 1; - if (maxy < env.maxy) return -1; - if (maxy > env.maxy) return 1; - return 0; - - - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/Geometry.java b/src/main/java/com/vividsolutions/jts/geom/Geometry.java deleted file mode 100644 index 7d864b716f..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Geometry.java +++ /dev/null @@ -1,1889 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; -import java.util.*; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.io.WKTWriter; -import com.vividsolutions.jts.operation.*; -import com.vividsolutions.jts.operation.buffer.BufferOp; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.linemerge.LineMerger; -import com.vividsolutions.jts.operation.overlay.OverlayOp; -import com.vividsolutions.jts.operation.union.UnaryUnionOp; -import com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp; -import com.vividsolutions.jts.operation.predicate.RectangleIntersects; -import com.vividsolutions.jts.operation.predicate.RectangleContains; -import com.vividsolutions.jts.operation.relate.RelateOp; -import com.vividsolutions.jts.operation.valid.IsValidOp; -import com.vividsolutions.jts.util.Assert; - -/** - * A representation of a planar, linear vector geometry. - *

          - * - *

          Binary Predicates

          - * Because it is not clear at this time - * what semantics for spatial - * analysis methods involving GeometryCollections would be useful, - * GeometryCollections are not supported as arguments to binary - * predicates or the relate - * method. - * - *

          Overlay Methods

          - * - * The overlay methods - * return the most specific class possible to represent the result. If the - * result is homogeneous, a Point, LineString, or - * Polygon will be returned if the result contains a single - * element; otherwise, a MultiPoint, MultiLineString, - * or MultiPolygon will be returned. If the result is - * heterogeneous a GeometryCollection will be returned.

          - * - * Because it is not clear at this time what semantics for set-theoretic - * methods involving GeometryCollections would be useful, - * GeometryCollections - * are not supported as arguments to the set-theoretic methods. - * - *

          Representation of Computed Geometries

          - * - * The SFS states that the result - * of a set-theoretic method is the "point-set" result of the usual - * set-theoretic definition of the operation (SFS 3.2.21.1). However, there are - * sometimes many ways of representing a point set as a Geometry. - *

          - * - * The SFS does not specify an unambiguous representation of a given point set - * returned from a spatial analysis method. One goal of JTS is to make this - * specification precise and unambiguous. JTS uses a canonical form for - * Geometrys returned from overlay methods. The canonical - * form is a Geometry which is simple and noded: - *

            - *
          • Simple means that the Geometry returned will be simple according to - * the JTS definition of isSimple. - *
          • Noded applies only to overlays involving LineStrings. It - * means that all intersection points on LineStrings will be - * present as endpoints of LineStrings in the result. - *
          - * This definition implies that non-simple geometries which are arguments to - * spatial analysis methods must be subjected to a line-dissolve process to - * ensure that the results are simple. - * - *

          Constructed Points And The Precision Model

          - * - * The results computed by the set-theoretic methods may - * contain constructed points which are not present in the input Geometry - * s. These new points arise from intersections between line segments in the - * edges of the input Geometrys. In the general case it is not - * possible to represent constructed points exactly. This is due to the fact - * that the coordinates of an intersection point may contain twice as many bits - * of precision as the coordinates of the input line segments. In order to - * represent these constructed points explicitly, JTS must truncate them to fit - * the PrecisionModel.

          - * - * Unfortunately, truncating coordinates moves them slightly. Line segments - * which would not be coincident in the exact result may become coincident in - * the truncated representation. This in turn leads to "topology collapses" -- - * situations where a computed element has a lower dimension than it would in - * the exact result.

          - * - * When JTS detects topology collapses during the computation of spatial - * analysis methods, it will throw an exception. If possible the exception will - * report the location of the collapse.

          - * - *

          Geometry Equality

          - * - * There are two ways of comparing geometries for equality: - * structural equality and topological equality. - * - *

          Structural Equality

          - * - * Structural Equality is provided by the - * {@link #equalsExact(Geometry)} method. - * This implements a comparison based on exact, structural pointwise - * equality. - * The {@link #equals(Object)} is a synonym for this method, - * to provide structural equality semantics for - * use in Java collections. - * It is important to note that structural pointwise equality - * is easily affected by things like - * ring order and component order. In many situations - * it will be desirable to normalize geometries before - * comparing them (using the {@link #norm()} - * or {@link #normalize()} methods). - * {@link #equalsNorm(Geometry)} is provided - * as a convenience method to compute equality over - * normalized geometries, but it is expensive to use. - * Finally, {@link #equalsExact(Geometry, double)} - * allows using a tolerance value for point comparison. - * - * - *

          Topological Equality

          - * - * Topological Equality is provided by the - * {@link #equalsTopo(Geometry)} method. - * It implements the SFS definition of point-set equality - * defined in terms of the DE-9IM matrix. - * To support the SFS naming convention, the method - * {@link #equals(Geometry)} is also provided as a synonym. - * However, due to the potential for confusion with {@link #equals(Object)} - * its use is discouraged. - *

          - * Since {@link #equals(Object)} and {@link #hashCode()} are overridden, - * Geometries can be used effectively in Java collections. - * - *@version 1.7 - */ -public abstract class Geometry - implements Cloneable, Comparable, Serializable -{ - private static final long serialVersionUID = 8763622679187376702L; - - private static final Class[] sortedClasses = new Class[] { - Point.class, - MultiPoint.class, - LineString.class, - LinearRing.class, - MultiLineString.class, - Polygon.class, - MultiPolygon.class, - GeometryCollection.class }; - - private final static GeometryComponentFilter geometryChangedFilter = new GeometryComponentFilter() { - public void filter(Geometry geom) { - geom.geometryChangedAction(); - } - }; - - /** - * The bounding box of this Geometry. - */ - protected Envelope envelope; - - /** - * The {@link GeometryFactory} used to create this Geometry - */ - protected final GeometryFactory factory; - - /** - * The ID of the Spatial Reference System used by this Geometry - */ - protected int SRID; - - /** - * An object reference which can be used to carry ancillary data defined - * by the client. - */ - private Object userData = null; - - /** - * Creates a new Geometry via the specified GeometryFactory. - * - * @param factory - */ - public Geometry(GeometryFactory factory) { - this.factory = factory; - this.SRID = factory.getSRID(); - } - - /** - * Returns the name of this Geometry's actual class. - * - *@return the name of this Geometrys actual class - */ - public abstract String getGeometryType(); - - /** - * Returns true if the array contains any non-empty Geometrys. - * - *@param geometries an array of Geometrys; no elements may be - * null - *@return true if any of the Geometrys - * isEmpty methods return false - */ - protected static boolean hasNonEmptyElements(Geometry[] geometries) { - for (int i = 0; i < geometries.length; i++) { - if (!geometries[i].isEmpty()) { - return true; - } - } - return false; - } - - /** - * Returns true if the array contains any null elements. - * - *@param array an array to validate - *@return true if any of arrays elements are - * null - */ - protected static boolean hasNullElements(Object[] array) { - for (int i = 0; i < array.length; i++) { - if (array[i] == null) { - return true; - } - } - return false; - } - - /** - * Returns the ID of the Spatial Reference System used by the Geometry. - *

          - * - * JTS supports Spatial Reference System information in the simple way - * defined in the SFS. A Spatial Reference System ID (SRID) is present in - * each Geometry object. Geometry provides basic - * accessor operations for this field, but no others. The SRID is represented - * as an integer. - * - *@return the ID of the coordinate space in which the Geometry - * is defined. - * - */ - public int getSRID() { - return SRID; - } - /** - * Sets the ID of the Spatial Reference System used by the Geometry. - *

          - * NOTE: This method should only be used for exceptional circumstances or - * for backwards compatibility. Normally the SRID should be set on the - * {@link GeometryFactory} used to create the geometry. - * SRIDs set using this method will not be propagated to - * geometries returned by constructive methods. - * - * @see GeometryFactory - */ - public void setSRID(int SRID) { - this.SRID = SRID; - } - - /** - * Gets the factory which contains the context in which this geometry was created. - * - * @return the factory for this geometry - */ - public GeometryFactory getFactory() { - return factory; - } - - /** - * Gets the user data object for this geometry, if any. - * - * @return the user data object, or null if none set - */ - public Object getUserData() { - return userData; - } - - /** - * Returns the number of {@link Geometry}s in a {@link GeometryCollection} - * (or 1, if the geometry is not a collection). - * - * @return the number of geometries contained in this geometry - */ - public int getNumGeometries() { - return 1; - } - - /** - * Returns an element {@link Geometry} from a {@link GeometryCollection} - * (or this, if the geometry is not a collection). - * - * @param n the index of the geometry element - * @return the n'th geometry contained in this geometry - */ - public Geometry getGeometryN(int n) { - return this; - } - - - /** - * A simple scheme for applications to add their own custom data to a Geometry. - * An example use might be to add an object representing a Coordinate Reference System. - *

          - * Note that user data objects are not present in geometries created by - * construction methods. - * - * @param userData an object, the semantics for which are defined by the - * application using this Geometry - */ - public void setUserData(Object userData) { - this.userData = userData; - } - - - /** - * Returns the PrecisionModel used by the Geometry. - * - *@return the specification of the grid of allowable points, for this - * Geometry and all other Geometrys - */ - public PrecisionModel getPrecisionModel() { - return factory.getPrecisionModel(); - } - - /** - * Returns a vertex of this Geometry - * (usually, but not necessarily, the first one). - * The returned coordinate should not be assumed - * to be an actual Coordinate object used in - * the internal representation. - * - *@return a {@link Coordinate} which is a vertex of this Geometry. - *@return null if this Geometry is empty - */ - public abstract Coordinate getCoordinate(); - - /** - * Returns an array containing the values of all the vertices for - * this geometry. - * If the geometry is a composite, the array will contain all the vertices - * for the components, in the order in which the components occur in the geometry. - *

          - * In general, the array cannot be assumed to be the actual internal - * storage for the vertices. Thus modifying the array - * may not modify the geometry itself. - * Use the {@link CoordinateSequence#setOrdinate} method - * (possibly on the components) to modify the underlying data. - * If the coordinates are modified, - * {@link #geometryChanged} must be called afterwards. - * - *@return the vertices of this Geometry - *@see #geometryChanged - *@see CoordinateSequence#setOrdinate - */ - public abstract Coordinate[] getCoordinates(); - - /** - * Returns the count of this Geometrys vertices. The Geometry - * s contained by composite Geometrys must be - * Geometry's; that is, they must implement getNumPoints - * - *@return the number of vertices in this Geometry - */ - public abstract int getNumPoints(); - - /** - * Tests whether this {@link Geometry} is simple. - * The SFS definition of simplicity - * follows the general rule that a Geometry is simple if it has no points of - * self-tangency, self-intersection or other anomalous points. - *

          - * Simplicity is defined for each {@link Geometry} subclass as follows: - *

            - *
          • Valid polygonal geometries are simple, since their rings - * must not self-intersect. isSimple - * tests for this condition and reports false if it is not met. - * (This is a looser test than checking for validity). - *
          • Linear rings have the same semantics. - *
          • Linear geometries are simple iff they do not self-intersect at points - * other than boundary points. - *
          • Zero-dimensional geometries (points) are simple iff they have no - * repeated points. - *
          • Empty Geometrys are always simple. - *
              - * - * @return true if this Geometry is simple - * @see #isValid - */ - public boolean isSimple() - { - IsSimpleOp op = new IsSimpleOp(this); - return op.isSimple(); - } - - /** - * Tests whether this Geometry - * is topologically valid, according to the OGC SFS specification. - *

              - * For validity rules see the Javadoc for the specific Geometry subclass. - * - *@return true if this Geometry is valid - * - * @see IsValidOp - */ - public boolean isValid() - { - return IsValidOp.isValid(this); - } - - /** - * Tests whether the set of points covered by this Geometry is - * empty. - * - *@return true if this Geometry does not cover any points - */ - public abstract boolean isEmpty(); - - /** - * Returns the minimum distance between this Geometry - * and another Geometry. - * - * @param g the Geometry from which to compute the distance - * @return the distance between the geometries - * @return 0 if either input geometry is empty - * @throws IllegalArgumentException if g is null - */ - public double distance(Geometry g) - { - return DistanceOp.distance(this, g); - } - - /** - * Tests whether the distance from this Geometry - * to another is less than or equal to a specified value. - * - * @param geom the Geometry to check the distance to - * @param distance the distance value to compare - * @return true if the geometries are less than distance apart. - */ - public boolean isWithinDistance(Geometry geom, double distance) - { - double envDist = getEnvelopeInternal().distance(geom.getEnvelopeInternal()); - if (envDist > distance) - return false; - return DistanceOp.isWithinDistance(this, geom, distance); - /* - double geomDist = this.distance(geom); - if (geomDist > distance) - return false; - return true; - */ - } - - public boolean isRectangle() - { - // Polygon overrides to check for actual rectangle - return false; - } - - /** - * Returns the area of this Geometry. - * Areal Geometries have a non-zero area. - * They override this function to compute the area. - * Others return 0.0 - * - *@return the area of the Geometry - */ - public double getArea() - { - return 0.0; - } - - /** - * Returns the length of this Geometry. - * Linear geometries return their length. - * Areal geometries return their perimeter. - * They override this function to compute the area. - * Others return 0.0 - * - *@return the length of the Geometry - */ - public double getLength() - { - return 0.0; - } - - /** - * Computes the centroid of this Geometry. - * The centroid - * is equal to the centroid of the set of component Geometries of highest - * dimension (since the lower-dimension geometries contribute zero - * "weight" to the centroid). - *

              - * The centroid of an empty geometry is POINT EMPTY. - * - * @return a {@link Point} which is the centroid of this Geometry - */ - public Point getCentroid() - { - if (isEmpty()) - return factory.createPoint((Coordinate) null); - Coordinate centPt = Centroid.getCentroid(this); - return createPointFromInternalCoord(centPt, this); - } - - /** - * Computes an interior point of this Geometry. - * An interior point is guaranteed to lie in the interior of the Geometry, - * if it possible to calculate such a point exactly. Otherwise, - * the point may lie on the boundary of the geometry. - *

              - * The interior point of an empty geometry is POINT EMPTY. - * - * @return a {@link Point} which is in the interior of this Geometry - */ - public Point getInteriorPoint() - { - if (isEmpty()) - return factory.createPoint((Coordinate) null); - Coordinate interiorPt = null; - int dim = getDimension(); - if (dim == 0) { - InteriorPointPoint intPt = new InteriorPointPoint(this); - interiorPt = intPt.getInteriorPoint(); - } - else if (dim == 1) { - InteriorPointLine intPt = new InteriorPointLine(this); - interiorPt = intPt.getInteriorPoint(); - } - else { - InteriorPointArea intPt = new InteriorPointArea(this); - interiorPt = intPt.getInteriorPoint(); - } - return createPointFromInternalCoord(interiorPt, this); - } - - /** - * Returns the dimension of this geometry. - * The dimension of a geometry is is the topological - * dimension of its embedding in the 2-D Euclidean plane. - * In the JTS spatial model, dimension values are in the set {0,1,2}. - *

              - * Note that this is a different concept to the dimension of - * the vertex {@link Coordinate}s. - * The geometry dimension can never be greater than the coordinate dimension. - * For example, a 0-dimensional geometry (e.g. a Point) - * may have a coordinate dimension of 3 (X,Y,Z). - * - *@return the topological dimension of this geometry. - */ - public abstract int getDimension(); - - /** - * Returns the boundary, or an empty geometry of appropriate dimension - * if this Geometry is empty. - * (In the case of zero-dimensional geometries, ' - * an empty GeometryCollection is returned.) - * For a discussion of this function, see the OpenGIS Simple - * Features Specification. As stated in SFS Section 2.1.13.1, "the boundary - * of a Geometry is a set of Geometries of the next lower dimension." - * - *@return the closure of the combinatorial boundary of this Geometry - */ - public abstract Geometry getBoundary(); - - /** - * Returns the dimension of this Geometrys inherent boundary. - * - *@return the dimension of the boundary of the class implementing this - * interface, whether or not this object is the empty geometry. Returns - * Dimension.FALSE if the boundary is the empty geometry. - */ - public abstract int getBoundaryDimension(); - - /** - * Gets a Geometry representing the envelope (bounding box) of - * this Geometry. - *

              - * If this Geometry is: - *

                - *
              • empty, returns an empty Point. - *
              • a point, returns a Point. - *
              • a line parallel to an axis, a two-vertex LineString - *
              • otherwise, returns a - * Polygon whose vertices are (minx miny, maxx miny, - * maxx maxy, minx maxy, minx miny). - *
              - * - *@return a Geometry representing the envelope of this Geometry - * - * @see GeometryFactory#toGeometry(Envelope) - */ - public Geometry getEnvelope() { - return getFactory().toGeometry(getEnvelopeInternal()); - } - - /** - * Gets an {@link Envelope} containing - * the minimum and maximum x and y values in this Geometry. - * If the geometry is empty, an empty Envelope - * is returned. - *

              - * The returned object is a copy of the one maintained internally, - * to avoid aliasing issues. - * For best performance, clients which access this - * envelope frequently should cache the return value. - * - *@return the envelope of this Geometry. - *@return an empty Envelope if this Geometry is empty - */ - public Envelope getEnvelopeInternal() { - if (envelope == null) { - envelope = computeEnvelopeInternal(); - } - return new Envelope(envelope); - } - - /** - * Notifies this geometry that its coordinates have been changed by an external - * party (for example, via a {@link CoordinateFilter}). - * When this method is called the geometry will flush - * and/or update any derived information it has cached (such as its {@link Envelope} ). - * The operation is applied to all component Geometries. - */ - public void geometryChanged() { - apply(geometryChangedFilter); - } - - /** - * Notifies this Geometry that its Coordinates have been changed by an external - * party. When #geometryChanged is called, this method will be called for - * this Geometry and its component Geometries. - * - * @see #apply(GeometryComponentFilter) - */ - protected void geometryChangedAction() { - envelope = null; - } - - /** - * Tests whether this geometry is disjoint from the argument geometry. - *

              - * The disjoint predicate has the following equivalent definitions: - *

                - *
              • The two geometries have no point in common - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * [FF*FF****] - *
              • ! g.intersects(this) = true - *
                (disjoint is the inverse of intersects) - *
              - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys are - * disjoint - * - * @see Geometry#intersects - */ - public boolean disjoint(Geometry g) { - return ! intersects(g); - } - - /** - * Tests whether this geometry touches the - * argument geometry. - *

              - * The touches predicate has the following equivalent definitions: - *

                - *
              • The geometries have at least one point in common, - * but their interiors do not intersect. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * at least one of the following patterns - *
                  - *
                • [FT*******] - *
                • [F**T*****] - *
                • [F***T****] - *
                - *
              - * If both geometries have dimension 0, the predicate returns false, - * since points have only interiors. - * This predicate is symmetric. - * - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys touch; - * Returns false if both Geometrys are points - */ - public boolean touches(Geometry g) { - // short-circuit test - if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal())) - return false; - return relate(g).isTouches(getDimension(), g.getDimension()); - } - - /** - * Tests whether this geometry intersects the argument geometry. - *

              - * The intersects predicate has the following equivalent definitions: - *

                - *
              • The two geometries have at least one point in common - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * at least one of the patterns - *
                  - *
                • [T********] - *
                • [*T*******] - *
                • [***T*****] - *
                • [****T****] - *
                - *
              • ! g.disjoint(this) = true - *
                (intersects is the inverse of disjoint) - *
              - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys intersect - * - * @see Geometry#disjoint - */ - public boolean intersects(Geometry g) { - - // short-circuit envelope test - if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal())) - return false; - - /** - * TODO: (MD) Add optimizations: - * - * - for P-A case: - * If P is in env(A), test for point-in-poly - * - * - for A-A case: - * If env(A1).overlaps(env(A2)) - * test for overlaps via point-in-poly first (both ways) - * Possibly optimize selection of point to test by finding point of A1 - * closest to centre of env(A2). - * (Is there a test where we shouldn't bother - e.g. if env A - * is much smaller than env B, maybe there's no point in testing - * pt(B) in env(A)? - */ - - // optimization for rectangle arguments - if (isRectangle()) { - return RectangleIntersects.intersects((Polygon) this, g); - } - if (g.isRectangle()) { - return RectangleIntersects.intersects((Polygon) g, this); - } - // general case - return relate(g).isIntersects(); - } - - /** - * Tests whether this geometry crosses the - * argument geometry. - *

              - * The crosses predicate has the following equivalent definitions: - *

                - *
              • The geometries have some but not all interior points in common. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * one of the following patterns: - *
                  - *
                • [T*T******] (for P/L, P/A, and L/A situations) - *
                • [T*****T**] (for L/P, A/P, and A/L situations) - *
                • [0********] (for L/L situations) - *
                - *
              - * For any other combination of dimensions this predicate returns false. - *

              - * The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. - * In order to make the relation symmetric, - * JTS extends the definition to apply to L/P, A/P and A/L situations as well. - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys cross. - */ - public boolean crosses(Geometry g) { - // short-circuit test - if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal())) - return false; - return relate(g).isCrosses(getDimension(), g.getDimension()); - } - - /** - * Tests whether this geometry is within the - * specified geometry. - *

              - * The within predicate has the following equivalent definitions: - *

                - *
              • Every point of this geometry is a point of the other geometry, - * and the interiors of the two geometries have at least one point in common. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * [T*F**F***] - *
              • g.contains(this) = true - *
                (within is the converse of {@link #contains}) - *
              - * An implication of the definition is that - * "The boundary of a Geometry is not within the Geometry". - * In other words, if a geometry A is a subset of - * the points in the boundary of a geomtry B, A.within(B) = false - * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) - * For a predicate with similar behaviour but avoiding - * this subtle limitation, see {@link #coveredBy}. - * - *@param g the Geometry with which to compare this Geometry - *@return true if this Geometry is within - * g - * - * @see Geometry#contains - * @see Geometry#coveredBy - */ - public boolean within(Geometry g) { - return g.contains(this); - } - - /** - * Tests whether this geometry contains the - * argument geometry. - *

              - * The contains predicate has the following equivalent definitions: - *

                - *
              • Every point of the other geometry is a point of this geometry, - * and the interiors of the two geometries have at least one point in common. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * the pattern - * [T*****FF*] - *
              • g.within(this) = true - *
                (contains is the converse of {@link #within} ) - *
              - * An implication of the definition is that "Geometries do not - * contain their boundary". In other words, if a geometry A is a subset of - * the points in the boundary of a geometry B, B.contains(A) = false. - * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) - * For a predicate with similar behaviour but avoiding - * this subtle limitation, see {@link #covers}. - * - *@param g the Geometry with which to compare this Geometry - *@return true if this Geometry contains g - * - * @see Geometry#within - * @see Geometry#covers - */ - public boolean contains(Geometry g) { - // short-circuit test - if (! getEnvelopeInternal().contains(g.getEnvelopeInternal())) - return false; - // optimization for rectangle arguments - if (isRectangle()) { - return RectangleContains.contains((Polygon) this, g); - } - // general case - return relate(g).isContains(); - } - - /** - * Tests whether this geometry overlaps the - * specified geometry. - *

              - * The overlaps predicate has the following equivalent definitions: - *

                - *
              • The geometries have at least one point each not shared by the other - * (or equivalently neither covers the other), - * they have the same dimension, - * and the intersection of the interiors of the two geometries has - * the same dimension as the geometries themselves. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * [T*T***T**] (for two points or two surfaces) - * or [1*T***T**] (for two curves) - *
              - * If the geometries are of different dimension this predicate returns false. - * This predicate is symmetric. - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys overlap. - */ - public boolean overlaps(Geometry g) { - // short-circuit test - if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal())) - return false; - return relate(g).isOverlaps(getDimension(), g.getDimension()); - } - - /** - * Tests whether this geometry covers the - * argument geometry. - *

              - * The covers predicate has the following equivalent definitions: - *

                - *
              • Every point of the other geometry is a point of this geometry. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * at least one of the following patterns: - *
                  - *
                • [T*****FF*] - *
                • [*T****FF*] - *
                • [***T**FF*] - *
                • [****T*FF*] - *
                - *
              • g.coveredBy(this) = true - *
                (covers is the converse of {@link #coveredBy}) - *
              - * If either geometry is empty, the value of this predicate is false. - *

              - * This predicate is similar to {@link #contains}, - * but is more inclusive (i.e. returns true for more cases). - * In particular, unlike contains it does not distinguish between - * points in the boundary and in the interior of geometries. - * For most situations, covers should be used in preference to contains. - * As an added benefit, covers is more amenable to optimization, - * and hence should be more performant. - * - *@param g the Geometry with which to compare this Geometry - *@return true if this Geometry covers g - * - * @see Geometry#contains - * @see Geometry#coveredBy - */ - public boolean covers(Geometry g) { - // short-circuit test - if (! getEnvelopeInternal().covers(g.getEnvelopeInternal())) - return false; - // optimization for rectangle arguments - if (isRectangle()) { - // since we have already tested that the test envelope is covered - return true; - } - return relate(g).isCovers(); - } - - /** - * Tests whether this geometry is covered by the - * argument geometry. - *

              - * The coveredBy predicate has the following equivalent definitions: - *

                - *
              • Every point of this geometry is a point of the other geometry. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * at least one of the following patterns: - *
                  - *
                • [T*F**F***] - *
                • [*TF**F***] - *
                • [**FT*F***] - *
                • [**F*TF***] - *
                - *
              • g.covers(this) = true - *
                (coveredBy is the converse of {@link #covers}) - *
              - * If either geometry is empty, the value of this predicate is false. - *

              - * This predicate is similar to {@link #within}, - * but is more inclusive (i.e. returns true for more cases). - * - *@param g the Geometry with which to compare this Geometry - *@return true if this Geometry is covered by g - * - * @see Geometry#within - * @see Geometry#covers - */ - public boolean coveredBy(Geometry g) { - return g.covers(this); - } - - /** - * Tests whether the elements in the DE-9IM - * {@link IntersectionMatrix} for the two Geometrys match the elements in intersectionPattern. - * The pattern is a 9-character string, with symbols drawn from the following set: - *

                - *
              • 0 (dimension 0) - *
              • 1 (dimension 1) - *
              • 2 (dimension 2) - *
              • T ( matches 0, 1 or 2) - *
              • F ( matches FALSE) - *
              • * ( matches any value) - *
              - * For more information on the DE-9IM, see the OpenGIS Simple Features - * Specification. - * - *@param g the Geometry with which to compare - * this Geometry - *@param intersectionPattern the pattern against which to check the - * intersection matrix for the two Geometrys - *@return true if the DE-9IM intersection - * matrix for the two Geometrys match intersectionPattern - * @see IntersectionMatrix - */ - public boolean relate(Geometry g, String intersectionPattern) { - return relate(g).matches(intersectionPattern); - } - - /** - * Returns the DE-9IM {@link IntersectionMatrix} for the two Geometrys. - * - *@param g the Geometry with which to compare this Geometry - *@return an {@link IntersectionMatrix} describing the intersections of the interiors, - * boundaries and exteriors of the two Geometrys - */ - public IntersectionMatrix relate(Geometry g) { - checkNotGeometryCollection(this); - checkNotGeometryCollection(g); - return RelateOp.relate(this, g); - } - - /** - * Tests whether this geometry is - * topologically equal to the argument geometry. - *

              - * This method is included for backward compatibility reasons. - * It has been superseded by the {@link #equalsTopo(Geometry)} method, - * which has been named to clearly denote its functionality. - *

              - * This method should NOT be confused with the method - * {@link #equals(Object)}, which implements - * an exact equality comparison. - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys are topologically equal - * - *@see #equalsTopo(Geometry) - */ - public boolean equals(Geometry g) { - if (g == null) return false; - return equalsTopo(g); - } - - /** - * Tests whether this geometry is topologically equal to the argument geometry - * as defined by the SFS equals predicate. - *

              - * The SFS equals predicate has the following equivalent definitions: - *

                - *
              • The two geometries have at least one point in common, - * and no point of either geometry lies in the exterior of the other geometry. - *
              • The DE-9IM Intersection Matrix for the two geometries matches - * the pattern T*F**FFF* - *
                -   * T*F
                -   * **F
                -   * FF*
                -   * 
                - *
              - * Note that this method computes topologically equality. - * For structural equality, see {@link #equalsExact(Geometry)}. - * - *@param g the Geometry with which to compare this Geometry - *@return true if the two Geometrys are topologically equal - * - *@see #equalsExact(Geometry) - */ - public boolean equalsTopo(Geometry g) - { - // short-circuit test - if (! getEnvelopeInternal().equals(g.getEnvelopeInternal())) - return false; - return relate(g).isEquals(getDimension(), g.getDimension()); - } - - /** - * Tests whether this geometry is structurally and numerically equal - * to a given Object. - * If the argument Object is not a Geometry, - * the result is false. - * Otherwise, the result is computed using - * {@link #equalsExact(Geometry)}. - *

              - * This method is provided to fulfill the Java contract - * for value-based object equality. - * In conjunction with {@link #hashCode()} - * it provides semantics which are most useful - * for using - * Geometrys as keys and values in Java collections. - *

              - * Note that to produce the expected result the input geometries - * should be in normal form. It is the caller's - * responsibility to perform this where required - * (using {@link Geometry#norm() - * or {@link #normalize()} as appropriate). - * - * @param o the Object to compare - * @return true if this geometry is exactly equal to the argument - * - * @see #equalsExact(Geometry) - * @see #hashCode() - * @see #norm() - * @see #normalize() - */ - public boolean equals(Object o) - { - if (! (o instanceof Geometry)) return false; - Geometry g = (Geometry) o; - return equalsExact(g); - } - - /** - * Gets a hash code for the Geometry. - * - * @return an integer value suitable for use as a hashcode - */ - public int hashCode() - { - return getEnvelopeInternal().hashCode(); - } - - public String toString() { - return toText(); - } - - /** - * Returns the Well-known Text representation of this Geometry. - * For a definition of the Well-known Text format, see the OpenGIS Simple - * Features Specification. - * - *@return the Well-known Text representation of this Geometry - */ - public String toText() { - WKTWriter writer = new WKTWriter(); - return writer.write(this); - } - - /** - * Computes a buffer area around this geometry having the given width. The - * buffer of a Geometry is the Minkowski sum or difference of the geometry - * with a disc of radius abs(distance). - *

              - * Mathematically-exact buffer area boundaries can contain circular arcs. - * To represent these arcs using linear geometry they must be approximated with line segments. - * The buffer geometry is constructed using 8 segments per quadrant to approximate - * the circular arcs. - * The end cap style is CAP_ROUND. - *

              - * The buffer operation always returns a polygonal result. The negative or - * zero-distance buffer of lines and points is always an empty {@link Polygon}. - * This is also the result for the buffers of degenerate (zero-area) polygons. - * - * @param distance - * the width of the buffer (may be positive, negative or 0) - * @return a polygonal geometry representing the buffer region (which may be - * empty) - * - * @throws TopologyException - * if a robustness error occurs - * - * @see #buffer(double, int) - * @see #buffer(double, int, int) - */ - public Geometry buffer(double distance) { - return BufferOp.bufferOp(this, distance); - } - - /** - * Computes a buffer area around this geometry having the given width and with - * a specified accuracy of approximation for circular arcs. - *

              - * Mathematically-exact buffer area boundaries can contain circular arcs. - * To represent these arcs - * using linear geometry they must be approximated with line segments. The - * quadrantSegments argument allows controlling the accuracy of - * the approximation by specifying the number of line segments used to - * represent a quadrant of a circle - *

              - * The buffer operation always returns a polygonal result. The negative or - * zero-distance buffer of lines and points is always an empty {@link Polygon}. - * This is also the result for the buffers of degenerate (zero-area) polygons. - * - * @param distance - * the width of the buffer (may be positive, negative or 0) - * @param quadrantSegments - * the number of line segments used to represent a quadrant of a - * circle - * @return a polygonal geometry representing the buffer region (which may be - * empty) - * - * @throws TopologyException - * if a robustness error occurs - * - * @see #buffer(double) - * @see #buffer(double, int, int) - */ - public Geometry buffer(double distance, int quadrantSegments) { - return BufferOp.bufferOp(this, distance, quadrantSegments); - } - - /** - * Computes a buffer area around this geometry having the given - * width and with a specified accuracy of approximation for circular arcs, - * and using a specified end cap style. - *

              - * Mathematically-exact buffer area boundaries can contain circular arcs. - * To represent these arcs using linear geometry they must be approximated with line segments. - * The quadrantSegments argument allows controlling the - * accuracy of the approximation - * by specifying the number of line segments used to represent a quadrant of a circle - *

              - * The end cap style specifies the buffer geometry that will be - * created at the ends of linestrings. The styles provided are: - *

                - *
              • BufferOp.CAP_ROUND - (default) a semi-circle - *
              • BufferOp.CAP_BUTT - a straight line perpendicular to the end segment - *
              • BufferOp.CAP_SQUARE - a half-square - *
              - *

              - * The buffer operation always returns a polygonal result. The negative or - * zero-distance buffer of lines and points is always an empty {@link Polygon}. - * This is also the result for the buffers of degenerate (zero-area) polygons. - * - *@param distance the width of the buffer (may be positive, negative or 0) - *@param quadrantSegments the number of line segments used to represent a quadrant of a circle - *@param endCapStyle the end cap style to use - *@return a polygonal geometry representing the buffer region (which may be empty) - * - * @throws TopologyException if a robustness error occurs - * - * @see #buffer(double) - * @see #buffer(double, int) - * @see BufferOp - */ - public Geometry buffer(double distance, int quadrantSegments, int endCapStyle) { - return BufferOp.bufferOp(this, distance, quadrantSegments, endCapStyle); - } - - /** - * Computes the smallest convex Polygon that contains all the - * points in the Geometry. This obviously applies only to Geometry - * s which contain 3 or more points; the results for degenerate cases are - * specified as follows: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
              Number of Points in argument Geometry Geometry class of result
              0 empty GeometryCollection
              1 Point
              2 LineString
              3 or more Polygon
              - * - *@return the minimum-area convex polygon containing this Geometry' - * s points - */ - public Geometry convexHull() { - return (new ConvexHull(this)).getConvexHull(); - } - - /** - * Computes a new geometry which has all component coordinate sequences - * in reverse order (opposite orientation) to this one. - * - * @return a reversed geometry - */ - public abstract Geometry reverse(); - - /** - * Computes a Geometry representing the point-set which is - * common to both this Geometry and the other Geometry. - *

              - * The intersection of two geometries of different dimension produces a result - * geometry of dimension less than or equal to the minimum dimension of the input - * geometries. - * The result geometry may be a heterogenous {@link GeometryCollection}. - * If the result is empty, it is an atomic geometry - * with the dimension of the lowest input dimension. - *

              - * Intersection of {@link GeometryCollection}s is supported - * only for homogeneous collection types. - *

              - * Non-empty heterogeneous {@link GeometryCollection} arguments are not supported. - * - * @param other the Geometry with which to compute the intersection - * @return a Geometry representing the point-set common to the two Geometrys - * @throws TopologyException if a robustness error occurs - * @throws IllegalArgumentException if the argument is a non-empty heterogeneous GeometryCollection - */ - public Geometry intersection(Geometry other) - { - /** - * TODO: MD - add optimization for P-A case using Point-In-Polygon - */ - // special case: if one input is empty ==> empty - if (this.isEmpty() || other.isEmpty()) - return OverlayOp.createEmptyResult(OverlayOp.INTERSECTION, this, other, factory); - - // compute for GCs - if (this.isGeometryCollection()) { - final Geometry g2 = other; - return GeometryCollectionMapper.map( - (GeometryCollection) this, - new GeometryMapper.MapOp() { - public Geometry map(Geometry g) { - return g.intersection(g2); - } - }); - } -// if (isGeometryCollection(other)) -// return other.intersection(this); - - checkNotGeometryCollection(this); - checkNotGeometryCollection(other); - return SnapIfNeededOverlayOp.overlayOp(this, other, OverlayOp.INTERSECTION); - } - - /** - * Computes a Geometry representing the point-set - * which is contained in both this - * Geometry and the other Geometry. - *

              - * The union of two geometries of different dimension produces a result - * geometry of dimension equal to the maximum dimension of the input - * geometries. - * The result geometry may be a heterogenous - * {@link GeometryCollection}. - * If the result is empty, it is an atomic geometry - * with the dimension of the highest input dimension. - *

              - * Unioning {@link LineString}s has the effect of - * noding and dissolving the input linework. In this context - * "noding" means that there will be a node or endpoint in the result for - * every endpoint or line segment crossing in the input. "Dissolving" means - * that any duplicate (i.e. coincident) line segments or portions of line - * segments will be reduced to a single line segment in the result. - * If merged linework is required, the {@link LineMerger} - * class can be used. - *

              - * Non-empty {@link GeometryCollection} arguments are not supported. - * - * @param other - * the Geometry with which to compute the union - * @return a point-set combining the points of this Geometry and the - * points of other - * @throws TopologyException - * if a robustness error occurs - * @throws IllegalArgumentException - * if either input is a non-empty GeometryCollection - * @see LineMerger - */ - public Geometry union(Geometry other) - { - // handle empty geometry cases - if (this.isEmpty() || other.isEmpty()) { - if (this.isEmpty() && other.isEmpty()) - return OverlayOp.createEmptyResult(OverlayOp.UNION, this, other, factory); - - // special case: if either input is empty ==> other input - if (this.isEmpty()) return (Geometry) other.clone(); - if (other.isEmpty()) return (Geometry) clone(); - } - - // TODO: optimize if envelopes of geometries do not intersect - - checkNotGeometryCollection(this); - checkNotGeometryCollection(other); - return SnapIfNeededOverlayOp.overlayOp(this, other, OverlayOp.UNION); - } - - /** - * Computes a Geometry representing the closure of the point-set - * of the points contained in this Geometry that are not contained in - * the other Geometry. - *

              - * If the result is empty, it is an atomic geometry - * with the dimension of the left-hand input. - *

              - * Non-empty {@link GeometryCollection} arguments are not supported. - * - *@param other the Geometry with which to compute the - * difference - *@return a Geometry representing the point-set difference of this Geometry with - * other - * @throws TopologyException if a robustness error occurs - * @throws IllegalArgumentException if either input is a non-empty GeometryCollection - */ - public Geometry difference(Geometry other) - { - // special case: if A.isEmpty ==> empty; if B.isEmpty ==> A - if (this.isEmpty()) return OverlayOp.createEmptyResult(OverlayOp.DIFFERENCE, this, other, factory); - if (other.isEmpty()) return (Geometry) clone(); - - checkNotGeometryCollection(this); - checkNotGeometryCollection(other); - return SnapIfNeededOverlayOp.overlayOp(this, other, OverlayOp.DIFFERENCE); - } - - /** - * Computes a Geometry representing the closure of the point-set - * which is the union of the points in this Geometry which are not - * contained in the other Geometry, - * with the points in the other Geometry not contained in this - * Geometry. - * If the result is empty, it is an atomic geometry - * with the dimension of the highest input dimension. - *

              - * Non-empty {@link GeometryCollection} arguments are not supported. - * - *@param other the Geometry with which to compute the symmetric - * difference - *@return a Geometry representing the point-set symmetric difference of this Geometry - * with other - * @throws TopologyException if a robustness error occurs - * @throws IllegalArgumentException if either input is a non-empty GeometryCollection - */ - public Geometry symDifference(Geometry other) - { - // handle empty geometry cases - if (this.isEmpty() || other.isEmpty()) { - // both empty - check dimensions - if (this.isEmpty() && other.isEmpty()) - return OverlayOp.createEmptyResult(OverlayOp.SYMDIFFERENCE, this, other, factory); - - // special case: if either input is empty ==> result = other arg - if (this.isEmpty()) return (Geometry) other.clone(); - if (other.isEmpty()) return (Geometry) clone(); - } - - checkNotGeometryCollection(this); - checkNotGeometryCollection(other); - return SnapIfNeededOverlayOp.overlayOp(this, other, OverlayOp.SYMDIFFERENCE); - } - - /** - * Computes the union of all the elements of this geometry. - *

              - * This method supports - * {@link GeometryCollection}s - * (which the other overlay operations currently do not). - *

              - * The result obeys the following contract: - *

                - *
              • Unioning a set of {@link LineString}s has the effect of fully noding - * and dissolving the linework. - *
              • Unioning a set of {@link Polygon}s always - * returns a {@link Polygonal} geometry (unlike {@link #union(Geometry)}, - * which may return geometries of lower dimension if a topology collapse occurred). - *
              - * - * @return the union geometry - * @throws TopologyException if a robustness error occurs - * - * @see UnaryUnionOp - */ - public Geometry union() { - return UnaryUnionOp.union(this); - } - - /** - * Returns true if the two Geometrys are exactly equal, - * up to a specified distance tolerance. - * Two Geometries are exactly equal within a distance tolerance - * if and only if: - *
                - *
              • they have the same structure - *
              • they have the same values for their vertices, - * within the given tolerance distance, in exactly the same order. - *
              - * This method does not - * test the values of the GeometryFactory, the SRID, - * or the userData fields. - *

              - * To properly test equality between different geometries, - * it is usually necessary to {@link #normalize()} them first. - * - * @param other the Geometry with which to compare this Geometry - * @param tolerance distance at or below which two Coordinates - * are considered equal - * @return true if this and the other Geometry - * have identical structure and point values, up to the distance tolerance. - * - * @see #equalsExact(Geometry) - * @see #normalize() - * @see #norm() - */ - public abstract boolean equalsExact(Geometry other, double tolerance); - - /** - * Returns true if the two Geometrys are exactly equal. - * Two Geometries are exactly equal iff: - *

                - *
              • they have the same structure - *
              • they have the same values for their vertices, - * in exactly the same order. - *
              - * This provides a stricter test of equality than - * {@link #equalsTopo(Geometry)}, which is more useful - * in certain situations - * (such as using geometries as keys in collections). - *

              - * This method does not - * test the values of the GeometryFactory, the SRID, - * or the userData fields. - *

              - * To properly test equality between different geometries, - * it is usually necessary to {@link #normalize()} them first. - * - *@param other the Geometry with which to compare this Geometry - *@return true if this and the other Geometry - * have identical structure and point values. - * - * @see #equalsExact(Geometry, double) - * @see #normalize() - * @see #norm() - */ - public boolean equalsExact(Geometry other) - { - return this == other || equalsExact(other, 0); - } - - /** - * Tests whether two geometries are exactly equal - * in their normalized forms. - * This is a convenience method which creates normalized - * versions of both geometries before computing - * {@link #equalsExact(Geometry)}. - *

              - * This method is relatively expensive to compute. - * For maximum performance, the client - * should instead perform normalization on the individual geometries - * at an appropriate point during processing. - * - * @param g a Geometry - * @return true if the input geometries are exactly equal in their normalized form - */ - public boolean equalsNorm(Geometry g) - { - if (g == null) return false; - return norm().equalsExact(g.norm()); - } - - - /** - * Performs an operation with or on this Geometry's - * coordinates. - * If this method modifies any coordinate values, - * {@link #geometryChanged} must be called to update the geometry state. - * Note that you cannot use this method to - * modify this Geometry if its underlying CoordinateSequence's #get method - * returns a copy of the Coordinate, rather than the actual Coordinate stored - * (if it even stores Coordinate objects at all). - * - *@param filter the filter to apply to this Geometry's - * coordinates - */ - public abstract void apply(CoordinateFilter filter); - - /** - * Performs an operation on the coordinates in this Geometry's - * {@link CoordinateSequence}s. - * If the filter reports that a coordinate value has been changed, - * {@link #geometryChanged} will be called automatically. - * - *@param filter the filter to apply - */ - public abstract void apply(CoordinateSequenceFilter filter); - - /** - * Performs an operation with or on this Geometry and its - * subelement Geometrys (if any). - * Only GeometryCollections and subclasses - * have subelement Geometry's. - * - *@param filter the filter to apply to this Geometry (and - * its children, if it is a GeometryCollection). - */ - public abstract void apply(GeometryFilter filter); - - /** - * Performs an operation with or on this Geometry and its - * component Geometry's. Only GeometryCollections and - * Polygons have component Geometry's; for Polygons they are the LinearRings - * of the shell and holes. - * - *@param filter the filter to apply to this Geometry. - */ - public abstract void apply(GeometryComponentFilter filter); - - /** - * Creates and returns a full copy of this {@link Geometry} object - * (including all coordinates contained by it). - * Subclasses are responsible for overriding this method and copying - * their internal data. Overrides should call this method first. - * - * @return a clone of this instance - */ - public Object clone() { - try { - Geometry clone = (Geometry) super.clone(); - if (clone.envelope != null) { clone.envelope = new Envelope(clone.envelope); } - return clone; - } - catch (CloneNotSupportedException e) { - Assert.shouldNeverReachHere(); - return null; - } - } - - /** - * Converts this Geometry to normal form (or - * canonical form ). Normal form is a unique representation for Geometry - * s. It can be used to test whether two Geometrys are equal - * in a way that is independent of the ordering of the coordinates within - * them. Normal form equality is a stronger condition than topological - * equality, but weaker than pointwise equality. The definitions for normal - * form use the standard lexicographical ordering for coordinates. "Sorted in - * order of coordinates" means the obvious extension of this ordering to - * sequences of coordinates. - *

              - * NOTE that this method mutates the value of this geometry in-place. - * If this is not safe and/or wanted, the geometry should be - * cloned prior to normalization. - */ - public abstract void normalize(); - - /** - * Creates a new Geometry which is a normalized - * copy of this Geometry. - * - * @return a normalized copy of this geometry. - * @see #normalize() - */ - public Geometry norm() - { - Geometry copy = (Geometry) clone(); - copy.normalize(); - return copy; - } - - /** - * Returns whether this Geometry is greater than, equal to, - * or less than another Geometry.

              - * - * If their classes are different, they are compared using the following - * ordering: - *

                - *
              • Point (lowest) - *
              • MultiPoint - *
              • LineString - *
              • LinearRing - *
              • MultiLineString - *
              • Polygon - *
              • MultiPolygon - *
              • GeometryCollection (highest) - *
              - * If the two Geometrys have the same class, their first - * elements are compared. If those are the same, the second elements are - * compared, etc. - * - *@param o a Geometry with which to compare this Geometry - *@return a positive number, 0, or a negative number, depending on whether - * this object is greater than, equal to, or less than o, as - * defined in "Normal Form For Geometry" in the JTS Technical - * Specifications - */ - public int compareTo(Object o) { - Geometry other = (Geometry) o; - if (getClassSortIndex() != other.getClassSortIndex()) { - return getClassSortIndex() - other.getClassSortIndex(); - } - if (isEmpty() && other.isEmpty()) { - return 0; - } - if (isEmpty()) { - return -1; - } - if (other.isEmpty()) { - return 1; - } - return compareToSameClass(o); - } - - /** - * Returns whether this Geometry is greater than, equal to, - * or less than another Geometry, - * using the given {@link CoordinateSequenceComparator}. - *

              - * - * If their classes are different, they are compared using the following - * ordering: - *

                - *
              • Point (lowest) - *
              • MultiPoint - *
              • LineString - *
              • LinearRing - *
              • MultiLineString - *
              • Polygon - *
              • MultiPolygon - *
              • GeometryCollection (highest) - *
              - * If the two Geometrys have the same class, their first - * elements are compared. If those are the same, the second elements are - * compared, etc. - * - *@param o a Geometry with which to compare this Geometry - *@param comp a CoordinateSequenceComparator - * - *@return a positive number, 0, or a negative number, depending on whether - * this object is greater than, equal to, or less than o, as - * defined in "Normal Form For Geometry" in the JTS Technical - * Specifications - */ - public int compareTo(Object o, CoordinateSequenceComparator comp) { - Geometry other = (Geometry) o; - if (getClassSortIndex() != other.getClassSortIndex()) { - return getClassSortIndex() - other.getClassSortIndex(); - } - if (isEmpty() && other.isEmpty()) { - return 0; - } - if (isEmpty()) { - return -1; - } - if (other.isEmpty()) { - return 1; - } - return compareToSameClass(o, comp); - } - - /** - * Returns whether the two Geometrys are equal, from the point - * of view of the equalsExact method. Called by equalsExact - * . In general, two Geometry classes are considered to be - * "equivalent" only if they are the same class. An exception is LineString - * , which is considered to be equivalent to its subclasses. - * - *@param other the Geometry with which to compare this Geometry - * for equality - *@return true if the classes of the two Geometry - * s are considered to be equal by the equalsExact method. - */ - protected boolean isEquivalentClass(Geometry other) { - return this.getClass().getName().equals(other.getClass().getName()); - } - - /** - * Throws an exception if g's class is GeometryCollection - * . (Its subclasses do not trigger an exception). - * - *@param g the Geometry to check - *@throws IllegalArgumentException if g is a GeometryCollection - * but not one of its subclasses - */ - protected void checkNotGeometryCollection(Geometry g) { - //Don't use instanceof because we want to allow subclasses - if (g.getClass().getName().equals("com.vividsolutions.jts.geom.GeometryCollection")) { - throw new IllegalArgumentException("This method does not support GeometryCollection arguments"); - } - } - - /** - * Tests whether this is an instance of a general {@link GeometryCollection}, - * rather than a homogeneous subclass. - * - * @return true if this is a hetereogeneous GeometryCollection - */ - protected boolean isGeometryCollection() - { - return getClass().equals(com.vividsolutions.jts.geom.GeometryCollection.class); - } - - /** - * Returns the minimum and maximum x and y values in this Geometry - * , or a null Envelope if this Geometry is empty. - * Unlike getEnvelopeInternal, this method calculates the Envelope - * each time it is called; getEnvelopeInternal caches the result - * of this method. - * - *@return this Geometrys bounding box; if the Geometry - * is empty, Envelope#isNull will return true - */ - protected abstract Envelope computeEnvelopeInternal(); - - /** - * Returns whether this Geometry is greater than, equal to, - * or less than another Geometry having the same class. - * - *@param o a Geometry having the same class as this Geometry - *@return a positive number, 0, or a negative number, depending on whether - * this object is greater than, equal to, or less than o, as - * defined in "Normal Form For Geometry" in the JTS Technical - * Specifications - */ - protected abstract int compareToSameClass(Object o); - - /** - * Returns whether this Geometry is greater than, equal to, - * or less than another Geometry of the same class. - * using the given {@link CoordinateSequenceComparator}. - * - *@param o a Geometry having the same class as this Geometry - *@param comp a CoordinateSequenceComparator - *@return a positive number, 0, or a negative number, depending on whether - * this object is greater than, equal to, or less than o, as - * defined in "Normal Form For Geometry" in the JTS Technical - * Specifications - */ - protected abstract int compareToSameClass(Object o, CoordinateSequenceComparator comp); - - /** - * Returns the first non-zero result of compareTo encountered as - * the two Collections are iterated over. If, by the time one of - * the iterations is complete, no non-zero result has been encountered, - * returns 0 if the other iteration is also complete. If b - * completes before a, a positive number is returned; if a - * before b, a negative number. - * - *@param a a Collection of Comparables - *@param b a Collection of Comparables - *@return the first non-zero compareTo result, if any; - * otherwise, zero - */ - protected int compare(Collection a, Collection b) { - Iterator i = a.iterator(); - Iterator j = b.iterator(); - while (i.hasNext() && j.hasNext()) { - Comparable aElement = (Comparable) i.next(); - Comparable bElement = (Comparable) j.next(); - int comparison = aElement.compareTo(bElement); - if (comparison != 0) { - return comparison; - } - } - if (i.hasNext()) { - return 1; - } - if (j.hasNext()) { - return -1; - } - return 0; - } - - protected boolean equal(Coordinate a, Coordinate b, double tolerance) { - if (tolerance == 0) { return a.equals(b); } - return a.distance(b) <= tolerance; - } - - private int getClassSortIndex() { - for (int i = 0; i < sortedClasses.length; i++) { - if (sortedClasses[i].isInstance(this)) - return i; - } - Assert.shouldNeverReachHere("Class not supported: " + this.getClass()); - return -1; - } - - private Point createPointFromInternalCoord(Coordinate coord, Geometry exemplar) - { - exemplar.getPrecisionModel().makePrecise(coord); - return exemplar.getFactory().createPoint(coord); - } - - -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/GeometryCollection.java b/src/main/java/com/vividsolutions/jts/geom/GeometryCollection.java deleted file mode 100644 index 891748fc3c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/GeometryCollection.java +++ /dev/null @@ -1,303 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.Arrays; -import java.util.TreeSet; - -import com.vividsolutions.jts.util.Assert; - -/** - * Models a collection of {@link Geometry}s of - * arbitrary type and dimension. - * - * - *@version 1.7 - */ -public class GeometryCollection extends Geometry { -// With contributions from Markus Schaber [schabios@logi-track.com] 2004-03-26 - private static final long serialVersionUID = -5694727726395021467L; - /** - * Internal representation of this GeometryCollection. - */ - protected Geometry[] geometries; - - /** @deprecated Use GeometryFactory instead */ - public GeometryCollection(Geometry[] geometries, PrecisionModel precisionModel, int SRID) { - this(geometries, new GeometryFactory(precisionModel, SRID)); - } - - - /** - * @param geometries - * the Geometrys for this GeometryCollection, - * or null or an empty array to create the empty - * geometry. Elements may be empty Geometrys, - * but not nulls. - */ - public GeometryCollection(Geometry[] geometries, GeometryFactory factory) { - super(factory); - if (geometries == null) { - geometries = new Geometry[]{}; - } - if (hasNullElements(geometries)) { - throw new IllegalArgumentException("geometries must not contain null elements"); - } - this.geometries = geometries; - } - - public Coordinate getCoordinate() { - if (isEmpty()) return null; - return geometries[0].getCoordinate(); - } - - /** - * Collects all coordinates of all subgeometries into an Array. - * - * Note that while changes to the coordinate objects themselves - * may modify the Geometries in place, the returned Array as such - * is only a temporary container which is not synchronized back. - * - * @return the collected coordinates - * */ - public Coordinate[] getCoordinates() { - Coordinate[] coordinates = new Coordinate[getNumPoints()]; - int k = -1; - for (int i = 0; i < geometries.length; i++) { - Coordinate[] childCoordinates = geometries[i].getCoordinates(); - for (int j = 0; j < childCoordinates.length; j++) { - k++; - coordinates[k] = childCoordinates[j]; - } - } - return coordinates; - } - - public boolean isEmpty() { - for (int i = 0; i < geometries.length; i++) { - if (!geometries[i].isEmpty()) { - return false; - } - } - return true; - } - - public int getDimension() { - int dimension = Dimension.FALSE; - for (int i = 0; i < geometries.length; i++) { - dimension = Math.max(dimension, geometries[i].getDimension()); - } - return dimension; - } - - public int getBoundaryDimension() { - int dimension = Dimension.FALSE; - for (int i = 0; i < geometries.length; i++) { - dimension = Math.max(dimension, ((Geometry) geometries[i]).getBoundaryDimension()); - } - return dimension; - } - - public int getNumGeometries() { - return geometries.length; - } - - public Geometry getGeometryN(int n) { - return geometries[n]; - } - - public int getNumPoints() { - int numPoints = 0; - for (int i = 0; i < geometries.length; i++) { - numPoints += ((Geometry) geometries[i]).getNumPoints(); - } - return numPoints; - } - - public String getGeometryType() { - return "GeometryCollection"; - } - - public Geometry getBoundary() { - checkNotGeometryCollection(this); - Assert.shouldNeverReachHere(); - return null; - } - - /** - * Returns the area of this GeometryCollection - * - * @return the area of the polygon - */ - public double getArea() - { - double area = 0.0; - for (int i = 0; i < geometries.length; i++) { - area += geometries[i].getArea(); - } - return area; - } - - public double getLength() - { - double sum = 0.0; - for (int i = 0; i < geometries.length; i++) { - sum += (geometries[i]).getLength(); - } - return sum; - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - GeometryCollection otherCollection = (GeometryCollection) other; - if (geometries.length != otherCollection.geometries.length) { - return false; - } - for (int i = 0; i < geometries.length; i++) { - if (!((Geometry) geometries[i]).equalsExact(otherCollection.geometries[i], tolerance)) { - return false; - } - } - return true; - } - - public void apply(CoordinateFilter filter) { - for (int i = 0; i < geometries.length; i++) { - geometries[i].apply(filter); - } - } - - public void apply(CoordinateSequenceFilter filter) { - if (geometries.length == 0) - return; - for (int i = 0; i < geometries.length; i++) { - geometries[i].apply(filter); - if (filter.isDone()) { - break; - } - } - if (filter.isGeometryChanged()) - geometryChanged(); - } - - public void apply(GeometryFilter filter) { - filter.filter(this); - for (int i = 0; i < geometries.length; i++) { - geometries[i].apply(filter); - } - } - - public void apply(GeometryComponentFilter filter) { - filter.filter(this); - for (int i = 0; i < geometries.length; i++) { - geometries[i].apply(filter); - } - } - - /** - * Creates and returns a full copy of this {@link GeometryCollection} object. - * (including all coordinates contained by it). - * - * @return a clone of this instance - */ - public Object clone() { - GeometryCollection gc = (GeometryCollection) super.clone(); - gc.geometries = new Geometry[geometries.length]; - for (int i = 0; i < geometries.length; i++) { - gc.geometries[i] = (Geometry) geometries[i].clone(); - } - return gc;// return the clone - } - - public void normalize() { - for (int i = 0; i < geometries.length; i++) { - geometries[i].normalize(); - } - Arrays.sort(geometries); - } - - protected Envelope computeEnvelopeInternal() { - Envelope envelope = new Envelope(); - for (int i = 0; i < geometries.length; i++) { - envelope.expandToInclude(geometries[i].getEnvelopeInternal()); - } - return envelope; - } - - protected int compareToSameClass(Object o) { - TreeSet theseElements = new TreeSet(Arrays.asList(geometries)); - TreeSet otherElements = new TreeSet(Arrays.asList(((GeometryCollection) o).geometries)); - return compare(theseElements, otherElements); - } - - protected int compareToSameClass(Object o, CoordinateSequenceComparator comp) { - GeometryCollection gc = (GeometryCollection) o; - - int n1 = getNumGeometries(); - int n2 = gc.getNumGeometries(); - int i = 0; - while (i < n1 && i < n2) { - Geometry thisGeom = getGeometryN(i); - Geometry otherGeom = gc.getGeometryN(i); - int holeComp = thisGeom.compareToSameClass(otherGeom, comp); - if (holeComp != 0) return holeComp; - i++; - } - if (i < n1) return 1; - if (i < n2) return -1; - return 0; - - } - - /** - * Creates a {@link GeometryCollection} with - * every component reversed. - * The order of the components in the collection are not reversed. - * - * @return a {@link GeometryCollection} in the reverse order - */ - public Geometry reverse() - { - int n = geometries.length; - Geometry[] revGeoms = new Geometry[n]; - for (int i = 0; i < geometries.length; i++) { - revGeoms[i] = geometries[i].reverse(); - } - return getFactory().createGeometryCollection(revGeoms); - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/GeometryCollectionIterator.java b/src/main/java/com/vividsolutions/jts/geom/GeometryCollectionIterator.java deleted file mode 100644 index bd44ee0e77..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/GeometryCollectionIterator.java +++ /dev/null @@ -1,160 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Iterates over all {@link Geometry}s in a {@link Geometry}, - * (which may be either a collection or an atomic geometry). - * The iteration sequence follows a pre-order, depth-first traversal of the - * structure of the GeometryCollection - * (which may be nested). The original Geometry object is - * returned as well (as the first object), as are all sub-collections and atomic elements. - * It is simple to ignore the intermediate GeometryCollection objects if they are not - * needed. - * - *@version 1.7 - */ -public class GeometryCollectionIterator implements Iterator { - - /** - * The Geometry being iterated over. - */ - private Geometry parent; - /** - * Indicates whether or not the first element - * (the root GeometryCollection) has been returned. - */ - private boolean atStart; - /** - * The number of Geometrys in the the GeometryCollection. - */ - private int max; - /** - * The index of the Geometry that will be returned when next - * is called. - */ - private int index; - /** - * The iterator over a nested Geometry, or null - * if this GeometryCollectionIterator is not currently iterating - * over a nested GeometryCollection. - */ - private GeometryCollectionIterator subcollectionIterator; - - /** - * Constructs an iterator over the given Geometry. - * - *@param parent the geometry over which to iterate; also, the first - * element returned by the iterator. - */ - public GeometryCollectionIterator(Geometry parent) { - this.parent = parent; - atStart = true; - index = 0; - max = parent.getNumGeometries(); - } - - /** - * Tests whether any geometry elements remain to be returned. - * - * @return true if more geometry elements remain - */ - public boolean hasNext() { - if (atStart) { - return true; - } - if (subcollectionIterator != null) { - if (subcollectionIterator.hasNext()) { - return true; - } - subcollectionIterator = null; - } - if (index >= max) { - return false; - } - return true; - } - - /** - * Gets the next geometry in the iteration sequence. - * - * @return the next geometry in the iteration - */ - public Object next() { - // the parent GeometryCollection is the first object returned - if (atStart) { - atStart = false; - if (isAtomic(parent)) - index++; - return parent; - } - if (subcollectionIterator != null) { - if (subcollectionIterator.hasNext()) { - return subcollectionIterator.next(); - } - else { - subcollectionIterator = null; - } - } - if (index >= max) { - throw new NoSuchElementException(); - } - Geometry obj = parent.getGeometryN(index++); - if (obj instanceof GeometryCollection) { - subcollectionIterator = new GeometryCollectionIterator((GeometryCollection) obj); - // there will always be at least one element in the sub-collection - return subcollectionIterator.next(); - } - return obj; - } - - private static boolean isAtomic(Geometry geom) - { - return ! (geom instanceof GeometryCollection); - } - - /** - * Removal is not supported. - * - * @throws UnsupportedOperationException This method is not implemented. - */ - public void remove() { - throw new UnsupportedOperationException(getClass().getName()); - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/GeometryComponentFilter.java b/src/main/java/com/vividsolutions/jts/geom/GeometryComponentFilter.java deleted file mode 100644 index 0bd4402ffb..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/GeometryComponentFilter.java +++ /dev/null @@ -1,68 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - - -/** - * Geometry classes support the concept of applying - * a GeometryComponentFilter - * filter to the Geometry. - * The filter is applied to every component of the Geometry - * which is itself a Geometry - * and which does not itself contain any components. - * (For instance, all the {@link LinearRing}s in {@link Polygon}s are visited, - * but in a {@link MultiPolygon} the {@link Polygon}s themselves are not visited.) - * Thus the only classes of Geometry which must be - * handled as arguments to {@link #filter} - * are {@link LineString}s, {@link LinearRing}s and {@link Point}s. - *

              - * A GeometryComponentFilter filter can either - * record information about the Geometry - * or change the Geometry in some way. - * GeometryComponentFilter - * is an example of the Gang-of-Four Visitor pattern. - * - *@version 1.7 - */ -public interface GeometryComponentFilter { - - /** - * Performs an operation with or on geom. - * - *@param geom a Geometry to which the filter is applied. - */ - void filter(Geometry geom); -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/GeometryFactory.java b/src/main/java/com/vividsolutions/jts/geom/GeometryFactory.java deleted file mode 100644 index a5e8d1ed48..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/GeometryFactory.java +++ /dev/null @@ -1,601 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.*; -import java.io.Serializable; -import com.vividsolutions.jts.geom.impl.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Supplies a set of utility methods for building Geometry objects from lists - * of Coordinates. - *

              - * Note that the factory constructor methods do not change the input coordinates in any way. - * In particular, they are not rounded to the supplied PrecisionModel. - * It is assumed that input Coordinates meet the given precision. - * - * - * @version 1.7 - */ -public class GeometryFactory - implements Serializable -{ - private static final long serialVersionUID = -6820524753094095635L; - private PrecisionModel precisionModel; - - private CoordinateSequenceFactory coordinateSequenceFactory; - - - public static Point createPointFromInternalCoord(Coordinate coord, Geometry exemplar) - { - exemplar.getPrecisionModel().makePrecise(coord); - return exemplar.getFactory().createPoint(coord); - } - - /** - * Constructs a GeometryFactory that generates Geometries having the given - * PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. - */ - public GeometryFactory(PrecisionModel precisionModel, int SRID, - CoordinateSequenceFactory coordinateSequenceFactory) { - this.precisionModel = precisionModel; - this.coordinateSequenceFactory = coordinateSequenceFactory; - this.SRID = SRID; - } - - /** - * Constructs a GeometryFactory that generates Geometries having the given - * CoordinateSequence implementation, a double-precision floating PrecisionModel and a - * spatial-reference ID of 0. - */ - public GeometryFactory(CoordinateSequenceFactory coordinateSequenceFactory) { - this(new PrecisionModel(), 0, coordinateSequenceFactory); - } - - /** - * Constructs a GeometryFactory that generates Geometries having the given - * {@link PrecisionModel} and the default CoordinateSequence - * implementation. - * - * @param precisionModel the PrecisionModel to use - */ - public GeometryFactory(PrecisionModel precisionModel) { - this(precisionModel, 0, getDefaultCoordinateSequenceFactory()); - } - - /** - * Constructs a GeometryFactory that generates Geometries having the given - * {@link PrecisionModel} and spatial-reference ID, and the default CoordinateSequence - * implementation. - * - * @param precisionModel the PrecisionModel to use - * @param SRID the SRID to use - */ - public GeometryFactory(PrecisionModel precisionModel, int SRID) { - this(precisionModel, SRID, getDefaultCoordinateSequenceFactory()); - } - - /** - * Constructs a GeometryFactory that generates Geometries having a floating - * PrecisionModel and a spatial-reference ID of 0. - */ - public GeometryFactory() { - this(new PrecisionModel(), 0); - } - - private static CoordinateSequenceFactory getDefaultCoordinateSequenceFactory() - { - return CoordinateArraySequenceFactory.instance(); - } - - /** - * Converts the List to an array. - * - *@param points the List of Points to convert - *@return the List in array format - */ - public static Point[] toPointArray(Collection points) { - Point[] pointArray = new Point[points.size()]; - return (Point[]) points.toArray(pointArray); - } - - /** - * Converts the List to an array. - * - *@param geometries the list of Geometry's to convert - *@return the List in array format - */ - public static Geometry[] toGeometryArray(Collection geometries) { - if (geometries == null) return null; - Geometry[] geometryArray = new Geometry[geometries.size()]; - return (Geometry[]) geometries.toArray(geometryArray); - } - - /** - * Converts the List to an array. - * - *@param linearRings the List of LinearRings to convert - *@return the List in array format - */ - public static LinearRing[] toLinearRingArray(Collection linearRings) { - LinearRing[] linearRingArray = new LinearRing[linearRings.size()]; - return (LinearRing[]) linearRings.toArray(linearRingArray); - } - - /** - * Converts the List to an array. - * - *@param lineStrings the List of LineStrings to convert - *@return the List in array format - */ - public static LineString[] toLineStringArray(Collection lineStrings) { - LineString[] lineStringArray = new LineString[lineStrings.size()]; - return (LineString[]) lineStrings.toArray(lineStringArray); - } - - /** - * Converts the List to an array. - * - *@param polygons the List of Polygons to convert - *@return the List in array format - */ - public static Polygon[] toPolygonArray(Collection polygons) { - Polygon[] polygonArray = new Polygon[polygons.size()]; - return (Polygon[]) polygons.toArray(polygonArray); - } - - /** - * Converts the List to an array. - * - *@param multiPolygons the List of MultiPolygons to convert - *@return the List in array format - */ - public static MultiPolygon[] toMultiPolygonArray(Collection multiPolygons) { - MultiPolygon[] multiPolygonArray = new MultiPolygon[multiPolygons.size()]; - return (MultiPolygon[]) multiPolygons.toArray(multiPolygonArray); - } - - /** - * Converts the List to an array. - * - *@param multiLineStrings the List of MultiLineStrings to convert - *@return the List in array format - */ - public static MultiLineString[] toMultiLineStringArray(Collection multiLineStrings) { - MultiLineString[] multiLineStringArray = new MultiLineString[multiLineStrings.size()]; - return (MultiLineString[]) multiLineStrings.toArray(multiLineStringArray); - } - - /** - * Converts the List to an array. - * - *@param multiPoints the List of MultiPoints to convert - *@return the List in array format - */ - public static MultiPoint[] toMultiPointArray(Collection multiPoints) { - MultiPoint[] multiPointArray = new MultiPoint[multiPoints.size()]; - return (MultiPoint[]) multiPoints.toArray(multiPointArray); - } - - /** - * Creates a {@link Geometry} with the same extent as the given envelope. - * The Geometry returned is guaranteed to be valid. - * To provide this behaviour, the following cases occur: - *

              - * If the Envelope is: - *

                - *
              • null : returns an empty {@link Point} - *
              • a point : returns a non-empty {@link Point} - *
              • a line : returns a two-point {@link LineString} - *
              • a rectangle : returns a {@link Polygon}> whose points are (minx, miny), - * (minx, maxy), (maxx, maxy), (maxx, miny), (minx, miny). - *
              - * - *@param envelope the Envelope to convert - *@return an empty Point (for null Envelopes), - * a Point (when min x = max x and min y = max y) or a - * Polygon (in all other cases) - */ - public Geometry toGeometry(Envelope envelope) - { - // null envelope - return empty point geometry - if (envelope.isNull()) { - return createPoint((CoordinateSequence)null); - } - - // point? - if (envelope.getMinX() == envelope.getMaxX() && envelope.getMinY() == envelope.getMaxY()) { - return createPoint(new Coordinate(envelope.getMinX(), envelope.getMinY())); - } - - // vertical or horizontal line? - if (envelope.getMinX() == envelope.getMaxX() - || envelope.getMinY() == envelope.getMaxY()) { - return createLineString(new Coordinate[]{ - new Coordinate(envelope.getMinX(), envelope.getMinY()), - new Coordinate(envelope.getMaxX(), envelope.getMaxY()) - }); - } - - // create a CW ring for the polygon - return createPolygon(createLinearRing(new Coordinate[]{ - new Coordinate(envelope.getMinX(), envelope.getMinY()), - new Coordinate(envelope.getMinX(), envelope.getMaxY()), - new Coordinate(envelope.getMaxX(), envelope.getMaxY()), - new Coordinate(envelope.getMaxX(), envelope.getMinY()), - new Coordinate(envelope.getMinX(), envelope.getMinY()) - }), null); - } - - /** - * Returns the PrecisionModel that Geometries created by this factory - * will be associated with. - * - * @return the PrecisionModel for this factory - */ - public PrecisionModel getPrecisionModel() { - return precisionModel; - } - - /** - * Creates a Point using the given Coordinate. - * A null Coordinate creates an empty Geometry. - * - * @param coordinate a Coordinate, or null - * @return the created Point - */ - public Point createPoint(Coordinate coordinate) { - return createPoint(coordinate != null ? getCoordinateSequenceFactory().create(new Coordinate[]{coordinate}) : null); - } - - /** - * Creates a Point using the given CoordinateSequence; a null or empty - * CoordinateSequence will create an empty Point. - * - * @param coordinates a CoordinateSequence (possibly empty), or null - * @return the created Point - */ - public Point createPoint(CoordinateSequence coordinates) { - return new Point(coordinates, this); - } - - /** - * Creates a MultiLineString using the given LineStrings; a null or empty - * array will create an empty MultiLineString. - * - * @param lineStrings LineStrings, each of which may be empty but not null - * @return the created MultiLineString - */ - public MultiLineString createMultiLineString(LineString[] lineStrings) { - return new MultiLineString(lineStrings, this); - } - - /** - * Creates a GeometryCollection using the given Geometries; a null or empty - * array will create an empty GeometryCollection. - * - * @param geometries an array of Geometries, each of which may be empty but not null, or null - * @return the created GeometryCollection - */ - public GeometryCollection createGeometryCollection(Geometry[] geometries) { - return new GeometryCollection(geometries, this); - } - - /** - * Creates a MultiPolygon using the given Polygons; a null or empty array - * will create an empty Polygon. The polygons must conform to the - * assertions specified in the
              OpenGIS Simple Features - * Specification for SQL. - * - * @param polygons - * Polygons, each of which may be empty but not null - * @return the created MultiPolygon - */ - public MultiPolygon createMultiPolygon(Polygon[] polygons) { - return new MultiPolygon(polygons, this); - } - - /** - * Creates a {@link LinearRing} using the given {@link Coordinate}s. - * A null or empty array creates an empty LinearRing. - * The points must form a closed and simple linestring. - * @param coordinates an array without null elements, or an empty array, or null - * @return the created LinearRing - * @throws IllegalArgumentException if the ring is not closed, or has too few points - */ - public LinearRing createLinearRing(Coordinate[] coordinates) { - return createLinearRing(coordinates != null ? getCoordinateSequenceFactory().create(coordinates) : null); - } - - /** - * Creates a {@link LinearRing} using the given {@link CoordinateSequence}. - * A null or empty array creates an empty LinearRing. - * The points must form a closed and simple linestring. - * - * @param coordinates a CoordinateSequence (possibly empty), or null - * @return the created LinearRing - * @throws IllegalArgumentException if the ring is not closed, or has too few points - */ - public LinearRing createLinearRing(CoordinateSequence coordinates) { - return new LinearRing(coordinates, this); - } - - /** - * Creates a {@link MultiPoint} using the given {@link Point}s. - * A null or empty array will create an empty MultiPoint. - * - * @param point an array of Points (without null elements), or an empty array, or null - * @return a MultiPoint object - */ - public MultiPoint createMultiPoint(Point[] point) { - return new MultiPoint(point, this); - } - - /** - * Creates a {@link MultiPoint} using the given {@link Coordinate}s. - * A null or empty array will create an empty MultiPoint. - * - * @param coordinates an array (without null elements), or an empty array, or null - * @return a MultiPoint object - */ - public MultiPoint createMultiPoint(Coordinate[] coordinates) { - return createMultiPoint(coordinates != null - ? getCoordinateSequenceFactory().create(coordinates) - : null); - } - - /** - * Creates a {@link MultiPoint} using the - * points in the given {@link CoordinateSequence}. - * A null or empty CoordinateSequence creates an empty MultiPoint. - * - * @param coordinates a CoordinateSequence (possibly empty), or null - * @return a MultiPoint geometry - */ - public MultiPoint createMultiPoint(CoordinateSequence coordinates) { - if (coordinates == null) { - return createMultiPoint(new Point[0]); - } - Point[] points = new Point[coordinates.size()]; - for (int i = 0; i < coordinates.size(); i++) { - CoordinateSequence ptSeq = getCoordinateSequenceFactory() - .create(1, coordinates.getDimension()); - CoordinateSequences.copy(coordinates, i, ptSeq, 0, 1); - points[i] = createPoint(ptSeq); - } - return createMultiPoint(points); - } - - /** - * Constructs a Polygon with the given exterior boundary and - * interior boundaries. - * - * @param shell - * the outer boundary of the new Polygon, or - * null or an empty LinearRing if - * the empty geometry is to be created. - * @param holes - * the inner boundaries of the new Polygon, or - * null or empty LinearRing s if - * the empty geometry is to be created. - * @throws IllegalArgumentException if a ring is invalid - */ - public Polygon createPolygon(LinearRing shell, LinearRing[] holes) { - return new Polygon(shell, holes, this); - } - - /** - * Constructs a Polygon with the given exterior boundary. - * - * @param shell - * the outer boundary of the new Polygon, or - * null or an empty LinearRing if - * the empty geometry is to be created. - * @throws IllegalArgumentException if the boundary ring is invalid - */ - public Polygon createPolygon(CoordinateSequence coordinates) { - return createPolygon(createLinearRing(coordinates)); - } - - /** - * Constructs a Polygon with the given exterior boundary. - * - * @param shell - * the outer boundary of the new Polygon, or - * null or an empty LinearRing if - * the empty geometry is to be created. - * @throws IllegalArgumentException if the boundary ring is invalid - */ - public Polygon createPolygon(Coordinate[] coordinates) { - return createPolygon(createLinearRing(coordinates)); - } - - /** - * Constructs a Polygon with the given exterior boundary. - * - * @param shell - * the outer boundary of the new Polygon, or - * null or an empty LinearRing if - * the empty geometry is to be created. - * @throws IllegalArgumentException if the boundary ring is invalid - */ - public Polygon createPolygon(LinearRing shell) { - return createPolygon(shell, null); - } - - /** - * Build an appropriate Geometry, MultiGeometry, or - * GeometryCollection to contain the Geometrys in - * it. - * For example:
              - * - *
                - *
              • If geomList contains a single Polygon, - * the Polygon is returned. - *
              • If geomList contains several Polygons, a - * MultiPolygon is returned. - *
              • If geomList contains some Polygons and - * some LineStrings, a GeometryCollection is - * returned. - *
              • If geomList is empty, an empty GeometryCollection - * is returned - *
              - * - * Note that this method does not "flatten" Geometries in the input, and hence if - * any MultiGeometries are contained in the input a GeometryCollection containing - * them will be returned. - * - *@param geomList the Geometrys to combine - *@return a Geometry of the "smallest", "most - * type-specific" class that can contain the elements of geomList - * . - */ - public Geometry buildGeometry(Collection geomList) { - - /** - * Determine some facts about the geometries in the list - */ - Class geomClass = null; - boolean isHeterogeneous = false; - boolean hasGeometryCollection = false; - for (Iterator i = geomList.iterator(); i.hasNext(); ) { - Geometry geom = (Geometry) i.next(); - Class partClass = geom.getClass(); - if (geomClass == null) { - geomClass = partClass; - } - if (partClass != geomClass) { - isHeterogeneous = true; - } - if (geom instanceof GeometryCollection) - hasGeometryCollection = true; - } - - /** - * Now construct an appropriate geometry to return - */ - // for the empty geometry, return an empty GeometryCollection - if (geomClass == null) { - return createGeometryCollection(null); - } - if (isHeterogeneous || hasGeometryCollection) { - return createGeometryCollection(toGeometryArray(geomList)); - } - // at this point we know the collection is hetereogenous. - // Determine the type of the result from the first Geometry in the list - // this should always return a geometry, since otherwise an empty collection would have already been returned - Geometry geom0 = (Geometry) geomList.iterator().next(); - boolean isCollection = geomList.size() > 1; - if (isCollection) { - if (geom0 instanceof Polygon) { - return createMultiPolygon(toPolygonArray(geomList)); - } - else if (geom0 instanceof LineString) { - return createMultiLineString(toLineStringArray(geomList)); - } - else if (geom0 instanceof Point) { - return createMultiPoint(toPointArray(geomList)); - } - Assert.shouldNeverReachHere("Unhandled class: " + geom0.getClass().getName()); - } - return geom0; - } - - /** - * Creates a LineString using the given Coordinates. - * A null or empty array creates an empty LineString. - * - * @param coordinates an array without null elements, or an empty array, or null - */ - public LineString createLineString(Coordinate[] coordinates) { - return createLineString(coordinates != null ? getCoordinateSequenceFactory().create(coordinates) : null); - } - /** - * Creates a LineString using the given CoordinateSequence. - * A null or empty CoordinateSequence creates an empty LineString. - * - * @param coordinates a CoordinateSequence (possibly empty), or null - */ - public LineString createLineString(CoordinateSequence coordinates) { - return new LineString(coordinates, this); - } - - /** - * Creates a deep copy of the input {@link Geometry}. - * The {@link CoordinateSequenceFactory} defined for this factory - * is used to copy the {@link CoordinateSequence}s - * of the input geometry. - *

              - * This is a convenient way to change the CoordinateSequence - * used to represent a geometry, or to change the - * factory used for a geometry. - *

              - * {@link Geometry#clone()} can also be used to make a deep copy, - * but it does not allow changing the CoordinateSequence type. - * - * @return a deep copy of the input geometry, using the CoordinateSequence type of this factory - * - * @see Geometry#clone() - */ - public Geometry createGeometry(Geometry g) - { - GeometryEditor editor = new GeometryEditor(this); - return editor.edit(g, new GeometryEditor.CoordinateSequenceOperation() { - public CoordinateSequence edit(CoordinateSequence coordSeq, Geometry geometry) { - return coordinateSequenceFactory.create(coordSeq); - } - }); - } - - /** - * Gets the SRID value defined for this factory. - * - * @return the factory SRID value - */ - public int getSRID() { - return SRID; - } - - private int SRID; - - public CoordinateSequenceFactory getCoordinateSequenceFactory() { - return coordinateSequenceFactory; - } - -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/GeometryFilter.java b/src/main/java/com/vividsolutions/jts/geom/GeometryFilter.java deleted file mode 100644 index 8cc5a4b8b2..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/GeometryFilter.java +++ /dev/null @@ -1,58 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - - -/** - * GeometryCollection classes support the concept of - * applying a GeometryFilter to the Geometry. - * The filter is applied to every element Geometry. - * A GeometryFilter can either record information about the Geometry - * or change the Geometry in some way. - * GeometryFilter - * is an example of the Gang-of-Four Visitor pattern. - * - *@version 1.7 - */ -public interface GeometryFilter { - - /** - * Performs an operation with or on geom. - * - *@param geom a Geometry to which the filter is applied. - */ - void filter(Geometry geom); -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/IntersectionMatrix.java b/src/main/java/com/vividsolutions/jts/geom/IntersectionMatrix.java deleted file mode 100644 index be3860d806..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/IntersectionMatrix.java +++ /dev/null @@ -1,598 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Models a Dimensionally Extended Nine-Intersection Model (DE-9IM) matrix. - * DE-9IM matrices (such as "212FF1FF2") - * specify the topological relationship between two {@link Geometry}s. - * This class can also represent matrix patterns (such as "T*T******") - * which are used for matching instances of DE-9IM matrices. - * - * Methods are provided to: - *

                - *
              • set and query the elements of the matrix in a convenient fashion - *
              • convert to and from the standard string representation (specified in - * SFS Section 2.1.13.2). - *
              • test to see if a matrix matches a given pattern string. - *
              - *

              - * - * For a description of the DE-9IM and the spatial predicates derived from it, - * see the OGC 99-049 OpenGIS Simple Features - * Specification for SQL, as well as - * OGC 06-103r4 OpenGIS - * Implementation Standard for Geographic information - - * Simple feature access - Part 1: Common architecture - * (which provides some further details on certain predicate specifications). - *

              - * The entries of the matrix are defined by the constants in the {@link Dimension} class. - * The indices of the matrix represent the topological locations - * that occur in a geometry (Interior, Boundary, Exterior). - * These are provided as constants in the {@link Location} class. - * - * - *@version 1.7 - */ -public class IntersectionMatrix implements Cloneable { - /** - * Internal representation of this IntersectionMatrix. - */ - private int[][] matrix; - - /** - * Creates an IntersectionMatrix with FALSE - * dimension values. - */ - public IntersectionMatrix() { - matrix = new int[3][3]; - setAll(Dimension.FALSE); - } - - /** - * Creates an IntersectionMatrix with the given dimension - * symbols. - * - *@param elements a String of nine dimension symbols in row major order - */ - public IntersectionMatrix(String elements) { - this(); - set(elements); - } - - /** - * Creates an IntersectionMatrix with the same elements as - * other. - * - *@param other an IntersectionMatrix to copy - */ - public IntersectionMatrix(IntersectionMatrix other) { - this(); - matrix[Location.INTERIOR][Location.INTERIOR] = other.matrix[Location.INTERIOR][Location.INTERIOR]; - matrix[Location.INTERIOR][Location.BOUNDARY] = other.matrix[Location.INTERIOR][Location.BOUNDARY]; - matrix[Location.INTERIOR][Location.EXTERIOR] = other.matrix[Location.INTERIOR][Location.EXTERIOR]; - matrix[Location.BOUNDARY][Location.INTERIOR] = other.matrix[Location.BOUNDARY][Location.INTERIOR]; - matrix[Location.BOUNDARY][Location.BOUNDARY] = other.matrix[Location.BOUNDARY][Location.BOUNDARY]; - matrix[Location.BOUNDARY][Location.EXTERIOR] = other.matrix[Location.BOUNDARY][Location.EXTERIOR]; - matrix[Location.EXTERIOR][Location.INTERIOR] = other.matrix[Location.EXTERIOR][Location.INTERIOR]; - matrix[Location.EXTERIOR][Location.BOUNDARY] = other.matrix[Location.EXTERIOR][Location.BOUNDARY]; - matrix[Location.EXTERIOR][Location.EXTERIOR] = other.matrix[Location.EXTERIOR][Location.EXTERIOR]; - } - - /** - * Adds one matrix to another. - * Addition is defined by taking the maximum dimension value of each position - * in the summand matrices. - * - * @param im the matrix to add - */ - public void add(IntersectionMatrix im) - { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - setAtLeast(i, j, im.get(i, j)); - } - } - } - - /** - * Tests if the dimension value matches TRUE - * (i.e. has value 0, 1, 2 or TRUE). - * - *@param actualDimensionValue a number that can be stored in the IntersectionMatrix - * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. - *@return true if the dimension value matches TRUE - */ - public static boolean isTrue(int actualDimensionValue) { - if (actualDimensionValue >= 0 || actualDimensionValue == Dimension.TRUE) { - return true; - } - return false; - } - - /** - * Tests if the dimension value satisfies the dimension symbol. - * - *@param actualDimensionValue a number that can be stored in the IntersectionMatrix - * . Possible values are {TRUE, FALSE, DONTCARE, 0, 1, 2}. - *@param requiredDimensionSymbol a character used in the string - * representation of an IntersectionMatrix. Possible values - * are {T, F, * , 0, 1, 2}. - *@return true if the dimension symbol matches - * the dimension value - */ - public static boolean matches(int actualDimensionValue, char requiredDimensionSymbol) { - if (requiredDimensionSymbol == Dimension.SYM_DONTCARE) { - return true; - } - if (requiredDimensionSymbol == Dimension.SYM_TRUE && (actualDimensionValue >= 0 || actualDimensionValue - == Dimension.TRUE)) { - return true; - } - if (requiredDimensionSymbol == Dimension.SYM_FALSE && actualDimensionValue == Dimension.FALSE) { - return true; - } - if (requiredDimensionSymbol == Dimension.SYM_P && actualDimensionValue == Dimension.P) { - return true; - } - if (requiredDimensionSymbol == Dimension.SYM_L && actualDimensionValue == Dimension.L) { - return true; - } - if (requiredDimensionSymbol == Dimension.SYM_A && actualDimensionValue == Dimension.A) { - return true; - } - return false; - } - - /** - * Tests if each of the actual dimension symbols in a matrix string satisfies the - * corresponding required dimension symbol in a pattern string. - * - *@param actualDimensionSymbols nine dimension symbols to validate. - * Possible values are {T, F, * , 0, 1, 2}. - *@param requiredDimensionSymbols nine dimension symbols to validate - * against. Possible values are {T, F, * , 0, 1, 2}. - *@return true if each of the required dimension - * symbols encompass the corresponding actual dimension symbol - */ - public static boolean matches(String actualDimensionSymbols, String requiredDimensionSymbols) { - IntersectionMatrix m = new IntersectionMatrix(actualDimensionSymbols); - return m.matches(requiredDimensionSymbols); - } - - /** - * Changes the value of one of this IntersectionMatrixs - * elements. - * - *@param row the row of this IntersectionMatrix, - * indicating the interior, boundary or exterior of the first Geometry - *@param column the column of this IntersectionMatrix, - * indicating the interior, boundary or exterior of the second Geometry - *@param dimensionValue the new value of the element - */ - public void set(int row, int column, int dimensionValue) { - matrix[row][column] = dimensionValue; - } - - /** - * Changes the elements of this IntersectionMatrix to the - * dimension symbols in dimensionSymbols. - * - *@param dimensionSymbols nine dimension symbols to which to set this IntersectionMatrix - * s elements. Possible values are {T, F, * , 0, 1, 2} - */ - public void set(String dimensionSymbols) { - for (int i = 0; i < dimensionSymbols.length(); i++) { - int row = i / 3; - int col = i % 3; - matrix[row][col] = Dimension.toDimensionValue(dimensionSymbols.charAt(i)); - } - } - - /** - * Changes the specified element to minimumDimensionValue if the - * element is less. - * - *@param row the row of this IntersectionMatrix - * , indicating the interior, boundary or exterior of the first Geometry - *@param column the column of this IntersectionMatrix - * , indicating the interior, boundary or exterior of the second Geometry - *@param minimumDimensionValue the dimension value with which to compare the - * element. The order of dimension values from least to greatest is - * {DONTCARE, TRUE, FALSE, 0, 1, 2}. - */ - public void setAtLeast(int row, int column, int minimumDimensionValue) { - if (matrix[row][column] < minimumDimensionValue) { - matrix[row][column] = minimumDimensionValue; - } - } - - /** - * If row >= 0 and column >= 0, changes the specified element to minimumDimensionValue - * if the element is less. Does nothing if row <0 or column < 0. - * - *@param row the row of this IntersectionMatrix - * , indicating the interior, boundary or exterior of the first Geometry - *@param column the column of this IntersectionMatrix - * , indicating the interior, boundary or exterior of the second Geometry - *@param minimumDimensionValue the dimension value with which to compare the - * element. The order of dimension values from least to greatest is - * {DONTCARE, TRUE, FALSE, 0, 1, 2}. - */ - public void setAtLeastIfValid(int row, int column, int minimumDimensionValue) { - if (row >= 0 && column >= 0) { - setAtLeast(row, column, minimumDimensionValue); - } - } - - /** - * For each element in this IntersectionMatrix, changes the - * element to the corresponding minimum dimension symbol if the element is - * less. - * - *@param minimumDimensionSymbols nine dimension symbols with which to - * compare the elements of this IntersectionMatrix. The - * order of dimension values from least to greatest is {DONTCARE, TRUE, FALSE, 0, 1, 2} - * . - */ - public void setAtLeast(String minimumDimensionSymbols) { - for (int i = 0; i < minimumDimensionSymbols.length(); i++) { - int row = i / 3; - int col = i % 3; - setAtLeast(row, col, Dimension.toDimensionValue(minimumDimensionSymbols.charAt(i))); - } - } - - /** - * Changes the elements of this IntersectionMatrix to dimensionValue - * . - * - *@param dimensionValue the dimension value to which to set this IntersectionMatrix - * s elements. Possible values {TRUE, FALSE, DONTCARE, 0, 1, 2} - * . - */ - public void setAll(int dimensionValue) { - for (int ai = 0; ai < 3; ai++) { - for (int bi = 0; bi < 3; bi++) { - matrix[ai][bi] = dimensionValue; - } - } - } - - /** - * Returns the value of one of this matrix - * entries. - * The value of the provided index is one of the - * values from the {@link Location} class. - * The value returned is a constant - * from the {@link Dimension} class. - * - *@param row the row of this IntersectionMatrix, indicating - * the interior, boundary or exterior of the first Geometry - *@param column the column of this IntersectionMatrix, - * indicating the interior, boundary or exterior of the second Geometry - *@return the dimension value at the given matrix position. - */ - public int get(int row, int column) { - return matrix[row][column]; - } - - /** - * Returns true if this IntersectionMatrix is - * FF*FF****. - * - *@return true if the two Geometrys related by - * this IntersectionMatrix are disjoint - */ - public boolean isDisjoint() { - return - matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && - matrix[Location.INTERIOR][Location.BOUNDARY] == Dimension.FALSE && - matrix[Location.BOUNDARY][Location.INTERIOR] == Dimension.FALSE && - matrix[Location.BOUNDARY][Location.BOUNDARY] == Dimension.FALSE; - } - - /** - * Returns true if isDisjoint returns false. - * - *@return true if the two Geometrys related by - * this IntersectionMatrix intersect - */ - public boolean isIntersects() { - return ! isDisjoint(); - } - - /** - * Returns true if this IntersectionMatrix is - * FT*******, F**T***** or F***T****. - * - *@param dimensionOfGeometryA the dimension of the first Geometry - *@param dimensionOfGeometryB the dimension of the second Geometry - *@return true if the two Geometry - * s related by this IntersectionMatrix touch; Returns false - * if both Geometrys are points. - */ - public boolean isTouches(int dimensionOfGeometryA, int dimensionOfGeometryB) { - if (dimensionOfGeometryA > dimensionOfGeometryB) { - //no need to get transpose because pattern matrix is symmetrical - return isTouches(dimensionOfGeometryB, dimensionOfGeometryA); - } - if ((dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A) || - (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) || - (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A) || - (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || - (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L)) { - return matrix[Location.INTERIOR][Location.INTERIOR] == Dimension.FALSE && - (isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) - || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) - || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY])); - } - return false; - } - - /** - * Tests whether this geometry crosses the - * specified geometry. - *

              - * The crosses predicate has the following equivalent definitions: - *

                - *
              • The geometries have some but not all interior points in common. - *
              • The DE-9IM Intersection Matrix for the two geometries is - *
                  - *
                • T*T****** (for P/L, P/A, and L/A situations) - *
                • T*****T** (for L/P, L/A, and A/L situations) - *
                • 0******** (for L/L situations) - *
                - *
              - * For any other combination of dimensions this predicate returns false. - *

              - * The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. - * JTS extends the definition to apply to L/P, A/P and A/L situations as well. - * This makes the relation symmetric. - * - *@param dimensionOfGeometryA the dimension of the first Geometry - *@param dimensionOfGeometryB the dimension of the second Geometry - *@return true if the two Geometrys - * related by this IntersectionMatrix cross. - */ - public boolean isCrosses(int dimensionOfGeometryA, int dimensionOfGeometryB) { - if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.L) || - (dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.A) || - (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.A)) { - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && - isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]); - } - if ((dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.P) || - (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.P) || - (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.L)) { - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && - isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); - } - if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { - return matrix[Location.INTERIOR][Location.INTERIOR] == 0; - } - return false; - } - - /** - * Tests whether this IntersectionMatrix is - * T*F**F***. - * - *@return true if the first Geometry is within - * the second - */ - public boolean isWithin() { - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && - matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && - matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; - } - - /** - * Tests whether this IntersectionMatrix is - * T*****FF*. - * - *@return true if the first Geometry contains the - * second - */ - public boolean isContains() { - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && - matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && - matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; - } - - /** - * Returns true if this IntersectionMatrix is - * T*****FF* - * or *T****FF* - * or ***T**FF* - * or ****T*FF* - * - *@return true if the first Geometry covers the - * second - */ - public boolean isCovers() { - boolean hasPointInCommon = - isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) - || isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) - || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) - || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); - - return hasPointInCommon && - matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && - matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; - } - - /** - * Returns true if this IntersectionMatrix is - * T*F**F*** - * or *TF**F*** - * or **FT*F*** - * or **F*TF*** - * - *@return true if the first Geometry - * is covered by the second - */ - public boolean isCoveredBy() { - boolean hasPointInCommon = - isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) - || isTrue(matrix[Location.INTERIOR][Location.BOUNDARY]) - || isTrue(matrix[Location.BOUNDARY][Location.INTERIOR]) - || isTrue(matrix[Location.BOUNDARY][Location.BOUNDARY]); - - return hasPointInCommon && - matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && - matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE; - } - - /** - * Tests whether the argument dimensions are equal and - * this IntersectionMatrix matches - * the pattern T*F**FFF*. - *

              - * Note: This pattern differs from the one stated in - * Simple feature access - Part 1: Common architecture. - * That document states the pattern as TFFFTFFFT. This would - * specify that - * two identical POINTs are not equal, which is not desirable behaviour. - * The pattern used here has been corrected to compute equality in this situation. - * - *@param dimensionOfGeometryA the dimension of the first Geometry - *@param dimensionOfGeometryB the dimension of the second Geometry - *@return true if the two Geometrys - * related by this IntersectionMatrix are equal; the - * Geometrys must have the same dimension to be equal - */ - public boolean isEquals(int dimensionOfGeometryA, int dimensionOfGeometryB) { - if (dimensionOfGeometryA != dimensionOfGeometryB) { - return false; - } - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) && - matrix[Location.INTERIOR][Location.EXTERIOR] == Dimension.FALSE && - matrix[Location.BOUNDARY][Location.EXTERIOR] == Dimension.FALSE && - matrix[Location.EXTERIOR][Location.INTERIOR] == Dimension.FALSE && - matrix[Location.EXTERIOR][Location.BOUNDARY] == Dimension.FALSE; - } - - /** - * Returns true if this IntersectionMatrix is - *

                - *
              • T*T***T** (for two points or two surfaces) - *
              • 1*T***T** (for two curves) - *
              . - * - *@param dimensionOfGeometryA the dimension of the first Geometry - *@param dimensionOfGeometryB the dimension of the second Geometry - *@return true if the two Geometrys - * related by this IntersectionMatrix overlap. For this - * function to return true, the Geometrys must - * be two points, two curves or two surfaces. - */ - public boolean isOverlaps(int dimensionOfGeometryA, int dimensionOfGeometryB) { - if ((dimensionOfGeometryA == Dimension.P && dimensionOfGeometryB == Dimension.P) || - (dimensionOfGeometryA == Dimension.A && dimensionOfGeometryB == Dimension.A)) { - return isTrue(matrix[Location.INTERIOR][Location.INTERIOR]) - && isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) - && isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); - } - if (dimensionOfGeometryA == Dimension.L && dimensionOfGeometryB == Dimension.L) { - return matrix[Location.INTERIOR][Location.INTERIOR] == 1 - && isTrue(matrix[Location.INTERIOR][Location.EXTERIOR]) - && isTrue(matrix[Location.EXTERIOR][Location.INTERIOR]); - } - return false; - } - - /** - * Returns whether the elements of this IntersectionMatrix - * satisfies the required dimension symbols. - * - *@param requiredDimensionSymbols nine dimension symbols with which to - * compare the elements of this IntersectionMatrix. Possible - * values are {T, F, * , 0, 1, 2}. - *@return true if this IntersectionMatrix - * matches the required dimension symbols - */ - public boolean matches(String requiredDimensionSymbols) { - if (requiredDimensionSymbols.length() != 9) { - throw new IllegalArgumentException("Should be length 9: " + requiredDimensionSymbols); - } - for (int ai = 0; ai < 3; ai++) { - for (int bi = 0; bi < 3; bi++) { - if (!matches(matrix[ai][bi], requiredDimensionSymbols.charAt(3 * ai + - bi))) { - return false; - } - } - } - return true; - } - - /** - * Transposes this IntersectionMatrix. - * - *@return this IntersectionMatrix as a convenience - */ - public IntersectionMatrix transpose() { - int temp = matrix[1][0]; - matrix[1][0] = matrix[0][1]; - matrix[0][1] = temp; - temp = matrix[2][0]; - matrix[2][0] = matrix[0][2]; - matrix[0][2] = temp; - temp = matrix[2][1]; - matrix[2][1] = matrix[1][2]; - matrix[1][2] = temp; - return this; - } - - /** - * Returns a nine-character String representation of this IntersectionMatrix - * . - * - *@return the nine dimension symbols of this IntersectionMatrix - * in row-major order. - */ - public String toString() { - StringBuffer buf = new StringBuffer("123456789"); - for (int ai = 0; ai < 3; ai++) { - for (int bi = 0; bi < 3; bi++) { - buf.setCharAt(3 * ai + bi, Dimension.toDimensionSymbol(matrix[ai][bi])); - } - } - return buf.toString(); - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/LineSegment.java b/src/main/java/com/vividsolutions/jts/geom/LineSegment.java deleted file mode 100644 index 3aae05b767..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/LineSegment.java +++ /dev/null @@ -1,670 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; - -import com.vividsolutions.jts.algorithm.*; - -/** - * Represents a line segment defined by two {@link Coordinate}s. - * Provides methods to compute various geometric properties - * and relationships of line segments. - *

              - * This class is designed to be easily mutable (to the extent of - * having its contained points public). - * This supports a common pattern of reusing a single LineSegment - * object as a way of computing segment properties on the - * segments defined by arrays or lists of {@link Coordinate}s. - * - *@version 1.7 - */ -public class LineSegment - implements Comparable, Serializable -{ - private static final long serialVersionUID = 3252005833466256227L; - - public Coordinate p0, p1; - - public LineSegment(Coordinate p0, Coordinate p1) { - this.p0 = p0; - this.p1 = p1; - } - - public LineSegment(double x0, double y0, double x1, double y1) { - this(new Coordinate(x0, y0), new Coordinate(x1, y1)); - } - - public LineSegment(LineSegment ls) { - this(ls.p0, ls.p1); - } - - public LineSegment() { - this(new Coordinate(), new Coordinate()); - } - - public Coordinate getCoordinate(int i) - { - if (i == 0) return p0; - return p1; - } - - public void setCoordinates(LineSegment ls) - { - setCoordinates(ls.p0, ls.p1); - } - - public void setCoordinates(Coordinate p0, Coordinate p1) - { - this.p0.x = p0.x; - this.p0.y = p0.y; - this.p1.x = p1.x; - this.p1.y = p1.y; - } - - /** - * Gets the minimum X ordinate. - * @return the minimum X ordinate - */ - public double minX() { - return Math.min(p0.x, p1.x); - } - - /** - * Gets the maximum X ordinate. - * @return the maximum X ordinate - */ - public double maxX() { - return Math.max(p0.x, p1.x); - } - - /** - * Gets the minimum Y ordinate. - * @return the minimum Y ordinate - */ - public double minY() { - return Math.min(p0.y, p1.y); - } - - /** - * Gets the maximum Y ordinate. - * @return the maximum Y ordinate - */ - public double maxY() { - return Math.max(p0.y, p1.y); - } - - /** - * Computes the length of the line segment. - * @return the length of the line segment - */ - public double getLength() - { - return p0.distance(p1); - } - - /** - * Tests whether the segment is horizontal. - * - * @return true if the segment is horizontal - */ - public boolean isHorizontal() { return p0.y == p1.y; } - - /** - * Tests whether the segment is vertical. - * - * @return true if the segment is vertical - */ - public boolean isVertical() { return p0.x == p1.x; } - - /** - * Determines the orientation of a LineSegment relative to this segment. - * The concept of orientation is specified as follows: - * Given two line segments A and L, - *

                A is to the left of a segment L if A lies wholly in the - * closed half-plane lying to the left of L - *
              • A is to the right of a segment L if A lies wholly in the - * closed half-plane lying to the right of L - *
              • otherwise, A has indeterminate orientation relative to L. This - * happens if A is collinear with L or if A crosses the line determined by L. - *
              - * - * @param seg the LineSegment to compare - * - * @return 1 if seg is to the left of this segment - * @return -1 if seg is to the right of this segment - * @return 0 if seg is collinear to or crosses this segment - */ - public int orientationIndex(LineSegment seg) - { - int orient0 = CGAlgorithms.orientationIndex(p0, p1, seg.p0); - int orient1 = CGAlgorithms.orientationIndex(p0, p1, seg.p1); - // this handles the case where the points are L or collinear - if (orient0 >= 0 && orient1 >= 0) - return Math.max(orient0, orient1); - // this handles the case where the points are R or collinear - if (orient0 <= 0 && orient1 <= 0) - return Math.max(orient0, orient1); - // points lie on opposite sides ==> indeterminate orientation - return 0; - } - - /** - * Determines the orientation index of a {@link Coordinate} relative to this segment. - * The orientation index is as defined in {@link CGAlgorithms#computeOrientation}. - * - * @param p the coordinate to compare - * - * @return 1 (LEFT) if p is to the left of this segment - * @return -1 (RIGHT) if p is to the right of this segment - * @return 0 (COLLINEAR) if p is collinear with this segment - * - * @see CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate) - */ - public int orientationIndex(Coordinate p) - { - return CGAlgorithms.orientationIndex(p0, p1, p); - } - - /** - * Reverses the direction of the line segment. - */ - public void reverse() - { - Coordinate temp = p0; - p0 = p1; - p1 = temp; - } - - /** - * Puts the line segment into a normalized form. - * This is useful for using line segments in maps and indexes when - * topological equality rather than exact equality is desired. - * A segment in normalized form has the first point smaller - * than the second (according to the standard ordering on {@link Coordinate}). - */ - public void normalize() - { - if (p1.compareTo(p0) < 0) reverse(); - } - - /** - * Computes the angle that the vector defined by this segment - * makes with the X-axis. - * The angle will be in the range [ -PI, PI ] radians. - * - * @return the angle this segment makes with the X-axis (in radians) - */ - public double angle() - { - return Math.atan2(p1.y - p0.y, p1.x - p0.x); - } - - /** - * Computes the midpoint of the segment - * - * @return the midpoint of the segment - */ - public Coordinate midPoint() - { - return midPoint(p0, p1); - } - - /** - * Computes the midpoint of a segment - * - * @return the midpoint of the segment - */ - public static Coordinate midPoint(Coordinate p0, Coordinate p1) - { - return new Coordinate( (p0.x + p1.x) / 2, - (p0.y + p1.y) / 2); - } - - /** - * Computes the distance between this line segment and another segment. - * - * @return the distance to the other segment - */ - public double distance(LineSegment ls) - { - return CGAlgorithms.distanceLineLine(p0, p1, ls.p0, ls.p1); - } - - /** - * Computes the distance between this line segment and a given point. - * - * @return the distance from this segment to the given point - */ - public double distance(Coordinate p) - { - return CGAlgorithms.distancePointLine(p, p0, p1); - } - - /** - * Computes the perpendicular distance between the (infinite) line defined - * by this line segment and a point. - * - * @return the perpendicular distance between the defined line and the given point - */ - public double distancePerpendicular(Coordinate p) - { - return CGAlgorithms.distancePointLinePerpendicular(p, p0, p1); - } - - /** - * Computes the {@link Coordinate} that lies a given - * fraction along the line defined by this segment. - * A fraction of 0.0 returns the start point of the segment; - * a fraction of 1.0 returns the end point of the segment. - * If the fraction is < 0.0 or > 1.0 the point returned - * will lie before the start or beyond the end of the segment. - * - * @param segmentLengthFraction the fraction of the segment length along the line - * @return the point at that distance - */ - public Coordinate pointAlong(double segmentLengthFraction) - { - Coordinate coord = new Coordinate(); - coord.x = p0.x + segmentLengthFraction * (p1.x - p0.x); - coord.y = p0.y + segmentLengthFraction * (p1.y - p0.y); - return coord; - } - - /** - * Computes the {@link Coordinate} that lies a given - * fraction along the line defined by this segment and offset from - * the segment by a given distance. - * A fraction of 0.0 offsets from the start point of the segment; - * a fraction of 1.0 offsets from the end point of the segment. - * The computed point is offset to the left of the line if the offset distance is - * positive, to the right if negative. - * - * @param segmentLengthFraction the fraction of the segment length along the line - * @param offsetDistance the distance the point is offset from the segment - * (positive is to the left, negative is to the right) - * @return the point at that distance and offset - * - * @throws IllegalStateException if the segment has zero length - */ - public Coordinate pointAlongOffset(double segmentLengthFraction, double offsetDistance) - { - // the point on the segment line - double segx = p0.x + segmentLengthFraction * (p1.x - p0.x); - double segy = p0.y + segmentLengthFraction * (p1.y - p0.y); - - double dx = p1.x - p0.x; - double dy = p1.y - p0.y; - double len = Math.sqrt(dx * dx + dy * dy); - double ux = 0.0; - double uy = 0.0; - if (offsetDistance != 0.0) { - if (len <= 0.0) - throw new IllegalStateException("Cannot compute offset from zero-length line segment"); - - // u is the vector that is the length of the offset, in the direction of the segment - ux = offsetDistance * dx / len; - uy = offsetDistance * dy / len; - } - - // the offset point is the seg point plus the offset vector rotated 90 degrees CCW - double offsetx = segx - uy; - double offsety = segy + ux; - - Coordinate coord = new Coordinate(offsetx, offsety); - return coord; - } - - /** - * Computes the Projection Factor for the projection of the point p - * onto this LineSegment. The Projection Factor is the constant r - * by which the vector for this segment must be multiplied to - * equal the vector for the projection of p on the line - * defined by this segment. - *

              - * The projection factor will lie in the range (-inf, +inf), - * or be NaN if the line segment has zero length.. - * - * @param p the point to compute the factor for - * @return the projection factor for the point - */ - public double projectionFactor(Coordinate p) - { - if (p.equals(p0)) return 0.0; - if (p.equals(p1)) return 1.0; - // Otherwise, use comp.graphics.algorithms Frequently Asked Questions method - /* AC dot AB - r = --------- - ||AB||^2 - r has the following meaning: - r=0 P = A - r=1 P = B - r<0 P is on the backward extension of AB - r>1 P is on the forward extension of AB - 0[0.0, 1.0]) - * that the projection of a point occurs along this line segment. - * If the point is beyond either ends of the line segment, - * the closest fractional value (0.0 or 1.0) is returned. - *

              - * Essentially, this is the {@link #projectionFactor} clamped to - * the range [0.0, 1.0]. - * If the segment has zero length, 1.0 is returned. - * - * @param inputPt the point - * @return the fraction along the line segment the projection of the point occurs - */ - public double segmentFraction( - Coordinate inputPt) - { - double segFrac = projectionFactor(inputPt); - if (segFrac < 0.0) - segFrac = 0.0; - else if (segFrac > 1.0 || Double.isNaN(segFrac)) - segFrac = 1.0; - return segFrac; - } - - /** - * Compute the projection of a point onto the line determined - * by this line segment. - *

              - * Note that the projected point - * may lie outside the line segment. If this is the case, - * the projection factor will lie outside the range [0.0, 1.0]. - */ - public Coordinate project(Coordinate p) - { - if (p.equals(p0) || p.equals(p1)) return new Coordinate(p); - - double r = projectionFactor(p); - Coordinate coord = new Coordinate(); - coord.x = p0.x + r * (p1.x - p0.x); - coord.y = p0.y + r * (p1.y - p0.y); - return coord; - } - /** - * Project a line segment onto this line segment and return the resulting - * line segment. The returned line segment will be a subset of - * the target line line segment. This subset may be null, if - * the segments are oriented in such a way that there is no projection. - *

              - * Note that the returned line may have zero length (i.e. the same endpoints). - * This can happen for instance if the lines are perpendicular to one another. - * - * @param seg the line segment to project - * @return the projected line segment, or null if there is no overlap - */ - public LineSegment project(LineSegment seg) - { - double pf0 = projectionFactor(seg.p0); - double pf1 = projectionFactor(seg.p1); - // check if segment projects at all - if (pf0 >= 1.0 && pf1 >= 1.0) return null; - if (pf0 <= 0.0 && pf1 <= 0.0) return null; - - Coordinate newp0 = project(seg.p0); - if (pf0 < 0.0) newp0 = p0; - if (pf0 > 1.0) newp0 = p1; - - Coordinate newp1 = project(seg.p1); - if (pf1 < 0.0) newp1 = p0; - if (pf1 > 1.0) newp1 = p1; - - return new LineSegment(newp0, newp1); - } - /** - * Computes the closest point on this line segment to another point. - * @param p the point to find the closest point to - * @return a Coordinate which is the closest point on the line segment to the point p - */ - public Coordinate closestPoint(Coordinate p) - { - double factor = projectionFactor(p); - if (factor > 0 && factor < 1) { - return project(p); - } - double dist0 = p0.distance(p); - double dist1 = p1.distance(p); - if (dist0 < dist1) - return p0; - return p1; - } - /** - * Computes the closest points on two line segments. - * - * @param line the segment to find the closest point to - * @return a pair of Coordinates which are the closest points on the line segments - */ - public Coordinate[] closestPoints(LineSegment line) - { - // test for intersection - Coordinate intPt = intersection(line); - if (intPt != null) { - return new Coordinate[] { intPt, intPt }; - } - - /** - * if no intersection closest pair contains at least one endpoint. - * Test each endpoint in turn. - */ - Coordinate[] closestPt = new Coordinate[2]; - double minDistance = Double.MAX_VALUE; - double dist; - - Coordinate close00 = closestPoint(line.p0); - minDistance = close00.distance(line.p0); - closestPt[0] = close00; - closestPt[1] = line.p0; - - Coordinate close01 = closestPoint(line.p1); - dist = close01.distance(line.p1); - if (dist < minDistance) { - minDistance = dist; - closestPt[0] = close01; - closestPt[1] = line.p1; - } - - Coordinate close10 = line.closestPoint(p0); - dist = close10.distance(p0); - if (dist < minDistance) { - minDistance = dist; - closestPt[0] = p0; - closestPt[1] = close10; - } - - Coordinate close11 = line.closestPoint(p1); - dist = close11.distance(p1); - if (dist < minDistance) { - minDistance = dist; - closestPt[0] = p1; - closestPt[1] = close11; - } - - return closestPt; - } - - /** - * Computes an intersection point between two line segments, if there is one. - * There may be 0, 1 or many intersection points between two segments. - * If there are 0, null is returned. If there is 1 or more, - * exactly one of them is returned - * (chosen at the discretion of the algorithm). - * If more information is required about the details of the intersection, - * the {@link RobustLineIntersector} class should be used. - * - * @param line a line segment - * @return an intersection point, or null if there is none - * - * @see RobustLineIntersector - */ - public Coordinate intersection(LineSegment line) - { - LineIntersector li = new RobustLineIntersector(); - li.computeIntersection(p0, p1, line.p0, line.p1); - if (li.hasIntersection()) - return li.getIntersection(0); - return null; - } - - /** - * Computes the intersection point of the lines of infinite extent defined - * by two line segments (if there is one). - * There may be 0, 1 or an infinite number of intersection points - * between two lines. - * If there is a unique intersection point, it is returned. - * Otherwise, null is returned. - * If more information is required about the details of the intersection, - * the {@link RobustLineIntersector} class should be used. - * - * @param line a line segment defining an straight line with infinite extent - * @return an intersection point, - * or null if there is no point of intersection - * or an infinite number of intersection points - * - * @see RobustLineIntersector - */ - public Coordinate lineIntersection(LineSegment line) - { - try { - Coordinate intPt = HCoordinate.intersection(p0, p1, line.p0, line.p1); - return intPt; - } - catch (NotRepresentableException ex) { - // eat this exception, and return null; - } - return null; - } - - /** - * Creates a LineString with the same coordinates as this segment - * - * @param geomFactory the geometery factory to use - * @return a LineString with the same geometry as this segment - */ - public LineString toGeometry(GeometryFactory geomFactory) - { - return geomFactory.createLineString(new Coordinate[] { p0, p1 }); - } - - /** - * Returns true if other has the same values for - * its points. - * - *@param o a LineSegment with which to do the comparison. - *@return true if other is a LineSegment - * with the same values for the x and y ordinates. - */ - public boolean equals(Object o) { - if (!(o instanceof LineSegment)) { - return false; - } - LineSegment other = (LineSegment) o; - return p0.equals(other.p0) && p1.equals(other.p1); - } - - /** - * Gets a hashcode for this object. - * - * @return a hashcode for this object - */ - public int hashCode() { - long bits0 = java.lang.Double.doubleToLongBits(p0.x); - bits0 ^= java.lang.Double.doubleToLongBits(p0.y) * 31; - int hash0 = (((int) bits0) ^ ((int) (bits0 >> 32))); - - long bits1 = java.lang.Double.doubleToLongBits(p1.x); - bits1 ^= java.lang.Double.doubleToLongBits(p1.y) * 31; - int hash1 = (((int) bits1) ^ ((int) (bits1 >> 32))); - - // XOR is supposed to be a good way to combine hashcodes - return hash0 ^ hash1; - } - - /** - * Compares this object with the specified object for order. - * Uses the standard lexicographic ordering for the points in the LineSegment. - * - *@param o the LineSegment with which this LineSegment - * is being compared - *@return a negative integer, zero, or a positive integer as this LineSegment - * is less than, equal to, or greater than the specified LineSegment - */ - public int compareTo(Object o) { - LineSegment other = (LineSegment) o; - int comp0 = p0.compareTo(other.p0); - if (comp0 != 0) return comp0; - return p1.compareTo(other.p1); - } - - /** - * Returns true if other is - * topologically equal to this LineSegment (e.g. irrespective - * of orientation). - * - *@param other a LineSegment with which to do the comparison. - *@return true if other is a LineSegment - * with the same values for the x and y ordinates. - */ - public boolean equalsTopo(LineSegment other) - { - return - p0.equals(other.p0) && p1.equals(other.p1) - || p0.equals(other.p1) && p1.equals(other.p0); - } - - public String toString() - { - return "LINESTRING( " + - p0.x + " " + p0.y - + ", " + - p1.x + " " + p1.y + ")"; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/LineString.java b/src/main/java/com/vividsolutions/jts/geom/LineString.java deleted file mode 100644 index f669a753aa..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/LineString.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.operation.BoundaryOp; - -/** - * Models an OGC-style LineString. - * A LineString consists of a sequence of two or more vertices, - * along with all points along the linearly-interpolated curves - * (line segments) between each - * pair of consecutive vertices. - * Consecutive vertices may be equal. - * The line segments in the line may intersect each other (in other words, - * the linestring may "curl back" in itself and self-intersect. - * Linestrings with exactly two identical points are invalid. - *

              - * A linestring must have either 0 or 2 or more points. - * If these conditions are not met, the constructors throw - * an {@link IllegalArgumentException} - * - *@version 1.7 - */ -public class LineString - extends Geometry - implements Lineal -{ - private static final long serialVersionUID = 3110669828065365560L; - /** - * The points of this LineString. - */ - protected CoordinateSequence points; - - /** - * Constructs a LineString with the given points. - * - *@param points the points of the linestring, or null - * to create the empty geometry. This array must not contain null - * elements. Consecutive points may be equal. - *@param precisionModel the specification of the grid of allowable points - * for this LineString - *@param SRID the ID of the Spatial Reference System used by this - * LineString - * @throws IllegalArgumentException if too few points are provided - */ - /** @deprecated Use GeometryFactory instead */ - public LineString(Coordinate points[], PrecisionModel precisionModel, int SRID) - { - super(new GeometryFactory(precisionModel, SRID)); - init(getFactory().getCoordinateSequenceFactory().create(points)); - } - - /** - * Constructs a LineString with the given points. - * - *@param points the points of the linestring, or null - * to create the empty geometry. - * @throws IllegalArgumentException if too few points are provided - */ - public LineString(CoordinateSequence points, GeometryFactory factory) { - super(factory); - init(points); - } - - private void init(CoordinateSequence points) - { - if (points == null) { - points = getFactory().getCoordinateSequenceFactory().create(new Coordinate[]{}); - } - if (points.size() == 1) { - throw new IllegalArgumentException("Invalid number of points in LineString (found " - + points.size() + " - must be 0 or >= 2)"); - } - this.points = points; - } - public Coordinate[] getCoordinates() { - return points.toCoordinateArray(); - } - - public CoordinateSequence getCoordinateSequence() { - return points; - } - - public Coordinate getCoordinateN(int n) { - return points.getCoordinate(n); - } - - public Coordinate getCoordinate() - { - if (isEmpty()) return null; - return points.getCoordinate(0); - } - - public int getDimension() { - return 1; - } - - public int getBoundaryDimension() { - if (isClosed()) { - return Dimension.FALSE; - } - return 0; - } - - public boolean isEmpty() { - return points.size() == 0; - } - - public int getNumPoints() { - return points.size(); - } - - public Point getPointN(int n) { - return getFactory().createPoint(points.getCoordinate(n)); - } - - public Point getStartPoint() { - if (isEmpty()) { - return null; - } - return getPointN(0); - } - - public Point getEndPoint() { - if (isEmpty()) { - return null; - } - return getPointN(getNumPoints() - 1); - } - - public boolean isClosed() { - if (isEmpty()) { - return false; - } - return getCoordinateN(0).equals2D(getCoordinateN(getNumPoints() - 1)); - } - - public boolean isRing() { - return isClosed() && isSimple(); - } - - public String getGeometryType() { - return "LineString"; - } - - /** - * Returns the length of this LineString - * - *@return the length of the linestring - */ - public double getLength() - { - return CGAlgorithms.length(points); - } - - /** - * Gets the boundary of this geometry. - * The boundary of a lineal geometry is always a zero-dimensional geometry (which may be empty). - * - * @return the boundary geometry - * @see Geometry#getBoundary - */ - public Geometry getBoundary() { - return (new BoundaryOp(this)).getBoundary(); - } - - /** - * Creates a {@link LineString} whose coordinates are in the reverse - * order of this objects - * - * @return a {@link LineString} with coordinates in the reverse order - */ - public Geometry reverse() - { - CoordinateSequence seq = (CoordinateSequence) points.clone(); - CoordinateSequences.reverse(seq); - LineString revLine = getFactory().createLineString(seq); - return revLine; - } - - /** - * Returns true if the given point is a vertex of this LineString. - * - *@param pt the Coordinate to check - *@return true if pt is one of this LineString - * 's vertices - */ - public boolean isCoordinate(Coordinate pt) { - for (int i = 0; i < points.size(); i++) { - if (points.getCoordinate(i).equals(pt)) { - return true; - } - } - return false; - } - - protected Envelope computeEnvelopeInternal() { - if (isEmpty()) { - return new Envelope(); - } - return points.expandEnvelope(new Envelope()); - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - LineString otherLineString = (LineString) other; - if (points.size() != otherLineString.points.size()) { - return false; - } - for (int i = 0; i < points.size(); i++) { - if (!equal(points.getCoordinate(i), otherLineString.points.getCoordinate(i), tolerance)) { - return false; - } - } - return true; - } - - public void apply(CoordinateFilter filter) { - for (int i = 0; i < points.size(); i++) { - filter.filter(points.getCoordinate(i)); - } - } - - public void apply(CoordinateSequenceFilter filter) - { - if (points.size() == 0) - return; - for (int i = 0; i < points.size(); i++) { - filter.filter(points, i); - if (filter.isDone()) - break; - } - if (filter.isGeometryChanged()) - geometryChanged(); - } - - public void apply(GeometryFilter filter) { - filter.filter(this); - } - - public void apply(GeometryComponentFilter filter) { - filter.filter(this); - } - - /** - * Creates and returns a full copy of this {@link LineString} object. - * (including all coordinates contained by it). - * - * @return a clone of this instance - */ - public Object clone() { - LineString ls = (LineString) super.clone(); - ls.points = (CoordinateSequence) points.clone(); - return ls; - } - - /** - * Normalizes a LineString. A normalized linestring - * has the first point which is not equal to it's reflected point - * less than the reflected point. - */ - public void normalize() - { - for (int i = 0; i < points.size() / 2; i++) { - int j = points.size() - 1 - i; - // skip equal points on both ends - if (!points.getCoordinate(i).equals(points.getCoordinate(j))) { - if (points.getCoordinate(i).compareTo(points.getCoordinate(j)) > 0) { - CoordinateSequences.reverse(points); - } - return; - } - } - } - - protected boolean isEquivalentClass(Geometry other) { - return other instanceof LineString; - } - - protected int compareToSameClass(Object o) - { - LineString line = (LineString) o; - // MD - optimized implementation - int i = 0; - int j = 0; - while (i < points.size() && j < line.points.size()) { - int comparison = points.getCoordinate(i).compareTo(line.points.getCoordinate(j)); - if (comparison != 0) { - return comparison; - } - i++; - j++; - } - if (i < points.size()) { - return 1; - } - if (j < line.points.size()) { - return -1; - } - return 0; - } - - protected int compareToSameClass(Object o, CoordinateSequenceComparator comp) - { - LineString line = (LineString) o; - return comp.compare(this.points, line.points); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/Lineal.java b/src/main/java/com/vividsolutions/jts/geom/Lineal.java deleted file mode 100644 index c655b42f0c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Lineal.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom; - -/** - * Identifies {@link Geometry} subclasses which - * are 1-dimensional and have components which are {@link LineString}s. - * - * @author Martin Davis - * - */ -public interface Lineal { - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/LinearRing.java b/src/main/java/com/vividsolutions/jts/geom/LinearRing.java deleted file mode 100644 index 312e8c4d07..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/LinearRing.java +++ /dev/null @@ -1,155 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Models an OGC SFS LinearRing. - * A LinearRing is a {@link LineString} which is both closed and simple. - * In other words, - * the first and last coordinate in the ring must be equal, - * and the interior of the ring must not self-intersect. - * Either orientation of the ring is allowed. - *

              - * A ring must have either 0 or 4 or more points. - * The first and last points must be equal (in 2D). - * If these conditions are not met, the constructors throw - * an {@link IllegalArgumentException} - * - * @version 1.7 - */ -public class LinearRing extends LineString -{ - /** - * The minimum number of vertices allowed in a valid non-empty ring (= 4). - * Empty rings with 0 vertices are also valid. - */ - public static final int MINIMUM_VALID_SIZE = 4; - - private static final long serialVersionUID = -4261142084085851829L; - - /** - * Constructs a LinearRing with the given points. - * - *@param points points forming a closed and simple linestring, or - * null or an empty array to create the empty geometry. - * This array must not contain null elements. - * - *@param precisionModel the specification of the grid of allowable points - * for this LinearRing - *@param SRID the ID of the Spatial Reference System used by this - * LinearRing - * @throws IllegalArgumentException if the ring is not closed, or has too few points - * - * @deprecated Use GeometryFactory instead - */ - public LinearRing(Coordinate points[], PrecisionModel precisionModel, - int SRID) { - this(points, new GeometryFactory(precisionModel, SRID)); - validateConstruction(); - } - - /** - * This method is ONLY used to avoid deprecation warnings. - * @param points - * @param factory - * @throws IllegalArgumentException if the ring is not closed, or has too few points - */ - private LinearRing(Coordinate points[], GeometryFactory factory) { - this(factory.getCoordinateSequenceFactory().create(points), factory); - } - - - /** - * Constructs a LinearRing with the vertices - * specifed by the given {@link CoordinateSequence}. - * - *@param points a sequence points forming a closed and simple linestring, or - * null to create the empty geometry. - * - * @throws IllegalArgumentException if the ring is not closed, or has too few points - * - */ - public LinearRing(CoordinateSequence points, GeometryFactory factory) { - super(points, factory); - validateConstruction(); - } - - private void validateConstruction() { - if (!isEmpty() && ! super.isClosed()) { - throw new IllegalArgumentException("Points of LinearRing do not form a closed linestring"); - } - if (getCoordinateSequence().size() >= 1 && getCoordinateSequence().size() < MINIMUM_VALID_SIZE) { - throw new IllegalArgumentException("Invalid number of points in LinearRing (found " - + getCoordinateSequence().size() + " - must be 0 or >= 4)"); - } - } - - /** - * Returns Dimension.FALSE, since by definition LinearRings do - * not have a boundary. - * - * @return Dimension.FALSE - */ - public int getBoundaryDimension() { - return Dimension.FALSE; - } - - /** - * Tests whether this ring is closed. - * Empty rings are closed by definition. - * - * @return true if this ring is closed - */ - public boolean isClosed() { - if (isEmpty()) { - // empty LinearRings are closed by definition - return true; - } - return super.isClosed(); - } - - - public String getGeometryType() { - return "LinearRing"; - } - - public Geometry reverse() - { - CoordinateSequence seq = (CoordinateSequence) points.clone(); - CoordinateSequences.reverse(seq); - LinearRing rev = getFactory().createLinearRing(seq); - return rev; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/Location.java b/src/main/java/com/vividsolutions/jts/geom/Location.java deleted file mode 100644 index 9c8533b29e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Location.java +++ /dev/null @@ -1,92 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Constants representing the different topological locations - * which can occur in a {@link Geometry}. - * The constants are also used as the row and column indices - * of DE-9IM {@link IntersectionMatrix}es. - * - *@version 1.7 - */ -public class Location { - /** - * The location value for the interior of a geometry. - * Also, DE-9IM row index of the interior of the first geometry and column index of - * the interior of the second geometry. - */ - public final static int INTERIOR = 0; - /** - * The location value for the boundary of a geometry. - * Also, DE-9IM row index of the boundary of the first geometry and column index of - * the boundary of the second geometry. - */ - public final static int BOUNDARY = 1; - /** - * The location value for the exterior of a geometry. - * Also, DE-9IM row index of the exterior of the first geometry and column index of - * the exterior of the second geometry. - */ - public final static int EXTERIOR = 2; - - /** - * Used for uninitialized location values. - */ - public final static int NONE = -1; - - /** - * Converts the location value to a location symbol, for example, EXTERIOR => 'e' - * . - * - *@param locationValue either EXTERIOR, BOUNDARY, INTERIOR or NONE - *@return either 'e', 'b', 'i' or '-' - */ - public static char toLocationSymbol(int locationValue) { - switch (locationValue) { - case EXTERIOR: - return 'e'; - case BOUNDARY: - return 'b'; - case INTERIOR: - return 'i'; - case NONE: - return '-'; - } - throw new IllegalArgumentException("Unknown location value: " + locationValue); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/geom/MultiLineString.java b/src/main/java/com/vividsolutions/jts/geom/MultiLineString.java deleted file mode 100644 index c3783cd1a1..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/MultiLineString.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import com.vividsolutions.jts.operation.BoundaryOp; - -/** - * Models a collection of (@link LineString}s. - *

              - * Any collection of LineStrings is a valid MultiLineString. - * - *@version 1.7 - */ -public class MultiLineString - extends GeometryCollection - implements Lineal - { - private static final long serialVersionUID = 8166665132445433741L; - /** - * Constructs a MultiLineString. - * - *@param lineStrings the LineStrings for this MultiLineString - * , or null or an empty array to create the empty geometry. - * Elements may be empty LineStrings, but not null - * s. - *@param precisionModel the specification of the grid of allowable points - * for this MultiLineString - *@param SRID the ID of the Spatial Reference System used by this - * MultiLineString - * @deprecated Use GeometryFactory instead - */ - public MultiLineString(LineString[] lineStrings, PrecisionModel precisionModel, int SRID) { - super(lineStrings, new GeometryFactory(precisionModel, SRID)); - } - - - - /** - * @param lineStrings - * the LineStrings for this MultiLineString, - * or null or an empty array to create the empty - * geometry. Elements may be empty LineStrings, - * but not nulls. - */ - public MultiLineString(LineString[] lineStrings, GeometryFactory factory) { - super(lineStrings, factory); - } - - public int getDimension() { - return 1; - } - - public int getBoundaryDimension() { - if (isClosed()) { - return Dimension.FALSE; - } - return 0; - } - - public String getGeometryType() { - return "MultiLineString"; - } - - public boolean isClosed() { - if (isEmpty()) { - return false; - } - for (int i = 0; i < geometries.length; i++) { - if (!((LineString) geometries[i]).isClosed()) { - return false; - } - } - return true; - } - - /** - * Gets the boundary of this geometry. - * The boundary of a lineal geometry is always a zero-dimensional geometry (which may be empty). - * - * @return the boundary geometry - * @see Geometry#getBoundary - */ - public Geometry getBoundary() - { - return (new BoundaryOp(this)).getBoundary(); - } - - /** - * Creates a {@link MultiLineString} in the reverse - * order to this object. - * Both the order of the component LineStrings - * and the order of their coordinate sequences - * are reversed. - * - * @return a {@link MultiLineString} in the reverse order - */ - public Geometry reverse() - { - int nLines = geometries.length; - LineString[] revLines = new LineString[nLines]; - for (int i = 0; i < geometries.length; i++) { - revLines[nLines - 1 - i] = (LineString)geometries[i].reverse(); - } - return getFactory().createMultiLineString(revLines); - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - return super.equalsExact(other, tolerance); - } - -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/MultiPoint.java b/src/main/java/com/vividsolutions/jts/geom/MultiPoint.java deleted file mode 100644 index f8b415a0c7..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/MultiPoint.java +++ /dev/null @@ -1,123 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Models a collection of {@link Point}s. - *

              - * Any collection of Points is a valid MultiPoint. - * - *@version 1.7 - */ -public class MultiPoint - extends GeometryCollection - implements Puntal -{ - - private static final long serialVersionUID = -8048474874175355449L; - - /** - * Constructs a MultiPoint. - * - *@param points the Points for this MultiPoint - * , or null or an empty array to create the empty geometry. - * Elements may be empty Points, but not nulls. - *@param precisionModel the specification of the grid of allowable points - * for this MultiPoint - *@param SRID the ID of the Spatial Reference System used by this - * MultiPoint - * @deprecated Use GeometryFactory instead - */ - public MultiPoint(Point[] points, PrecisionModel precisionModel, int SRID) { - super(points, new GeometryFactory(precisionModel, SRID)); - } - - /** - *@param points the Points for this MultiPoint - * , or null or an empty array to create the empty geometry. - * Elements may be empty Points, but not nulls. - */ - public MultiPoint(Point[] points, GeometryFactory factory) { - super(points, factory); - } - - public int getDimension() { - return 0; - } - - public int getBoundaryDimension() { - return Dimension.FALSE; - } - - public String getGeometryType() { - return "MultiPoint"; - } - - /** - * Gets the boundary of this geometry. - * Zero-dimensional geometries have no boundary by definition, - * so an empty GeometryCollection is returned. - * - * @return an empty GeometryCollection - * @see Geometry#getBoundary - */ - public Geometry getBoundary() { - return getFactory().createGeometryCollection(null); - } - - public boolean isValid() { - return true; - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - return super.equalsExact(other, tolerance); - } - - /** - * Returns the Coordinate at the given position. - * - *@param n the index of the Coordinate to retrieve, beginning - * at 0 - *@return the nth Coordinate - */ - protected Coordinate getCoordinate(int n) { - return ((Point) geometries[n]).getCoordinate(); - } - -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/MultiPolygon.java b/src/main/java/com/vividsolutions/jts/geom/MultiPolygon.java deleted file mode 100644 index f9166df7c9..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/MultiPolygon.java +++ /dev/null @@ -1,155 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.ArrayList; - -/** - * Models a collection of {@link Polygon}s. - *

              - * As per the OGC SFS specification, - * the Polygons in a MultiPolygon may not overlap, - * and may only touch at single points. - * This allows the topological point-set semantics - * to be well-defined. - * - * - *@version 1.7 - */ -public class MultiPolygon - extends GeometryCollection - implements Polygonal -{ - private static final long serialVersionUID = -551033529766975875L; - /** - * Constructs a MultiPolygon. - * - *@param polygons the Polygons for this MultiPolygon - * , or null or an empty array to create the empty geometry. - * Elements may be empty Polygons, but not null - * s. The polygons must conform to the assertions specified in the OpenGIS Simple Features - * Specification for SQL . - *@param precisionModel the specification of the grid of allowable points - * for this MultiPolygon - *@param SRID the ID of the Spatial Reference System used by this - * MultiPolygon - * @deprecated Use GeometryFactory instead - */ - public MultiPolygon(Polygon[] polygons, PrecisionModel precisionModel, int SRID) { - this(polygons, new GeometryFactory(precisionModel, SRID)); - } - - - /** - * @param polygons - * the Polygons for this MultiPolygon, - * or null or an empty array to create the empty - * geometry. Elements may be empty Polygons, but - * not nulls. The polygons must conform to the - * assertions specified in the OpenGIS Simple - * Features Specification for SQL. - */ - public MultiPolygon(Polygon[] polygons, GeometryFactory factory) { - super(polygons, factory); - } - - public int getDimension() { - return 2; - } - - public int getBoundaryDimension() { - return 1; - } - - public String getGeometryType() { - return "MultiPolygon"; - } - - /* - public boolean isSimple() { - return true; - } -*/ - - /** - * Computes the boundary of this geometry - * - * @return a lineal geometry (which may be empty) - * @see Geometry#getBoundary - */ - public Geometry getBoundary() { - if (isEmpty()) { - return getFactory().createMultiLineString(null); - } - ArrayList allRings = new ArrayList(); - for (int i = 0; i < geometries.length; i++) { - Polygon polygon = (Polygon) geometries[i]; - Geometry rings = polygon.getBoundary(); - for (int j = 0; j < rings.getNumGeometries(); j++) { - allRings.add(rings.getGeometryN(j)); - } - } - LineString[] allRingsArray = new LineString[allRings.size()]; - return getFactory().createMultiLineString((LineString[]) allRings.toArray(allRingsArray)); - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - return super.equalsExact(other, tolerance); - } - - /** - * Creates a {@link MultiPolygon} with - * every component reversed. - * The order of the components in the collection are not reversed. - * - * @return a MultiPolygon in the reverse order - */ - public Geometry reverse() - { - int n = geometries.length; - Polygon[] revGeoms = new Polygon[n]; - for (int i = 0; i < geometries.length; i++) { - revGeoms[i] = (Polygon) geometries[i].reverse(); - } - return getFactory().createMultiPolygon(revGeoms); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/geom/OctagonalEnvelope.java b/src/main/java/com/vividsolutions/jts/geom/OctagonalEnvelope.java deleted file mode 100644 index d2d03dce53..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/OctagonalEnvelope.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * A bounding container for a {@link Geometry} which is in the shape of a general octagon. - * The OctagonalEnvelope of a geometric object - * is a geometry which is a tight bound - * along the (up to) four extremal rectilinear parallels - * and along the (up to) four extremal diagonal parallels. - * Depending on the shape of the contained - * geometry, the octagon may be degenerate to any extreme - * (e.g. it may be a rectangle, a line, or a point). - */ -public class OctagonalEnvelope -{ - /** - * Gets the octagonal envelope of a geometry - * @param geom the geometry - * @return the octagonal envelope of the geometry - */ - public static Geometry octagonalEnvelope(Geometry geom) { - return (new OctagonalEnvelope(geom)).toGeometry(geom.getFactory()); - } - - private static double computeA(double x, double y) - { - return x + y; - } - - private static double computeB(double x, double y) - { - return x - y; - } - - private static double SQRT2 = Math.sqrt(2.0); - - // initialize in the null state - private double minX = Double.NaN; - private double maxX; - private double minY; - private double maxY; - private double minA; - private double maxA; - private double minB; - private double maxB; - - /** - * Creates a new null bounding octagon - */ - public OctagonalEnvelope() - { - } - - /** - * Creates a new null bounding octagon bounding a {@link Coordinate} - * - * @param p the coordinate to bound - */ - public OctagonalEnvelope(Coordinate p) - { - expandToInclude(p); - } - - /** - * Creates a new null bounding octagon bounding a pair of {@link Coordinate}s - * - * @param p1 a coordinate to bound - * @param p2 a coordinate to bound - */ - public OctagonalEnvelope(Coordinate p0, Coordinate p1) - { - expandToInclude(p0); - expandToInclude(p1); - } - - /** - * Creates a new null bounding octagon bounding an {@link Envelope} - */ - public OctagonalEnvelope(Envelope env) - { - expandToInclude(env); - } - - /** - * Creates a new null bounding octagon bounding an {@link OctagonalEnvelope} - * (the copy constructor). - */ - public OctagonalEnvelope(OctagonalEnvelope oct) - { - expandToInclude(oct); - } - - /** - * Creates a new null bounding octagon bounding a {@link Geometry} - */ - public OctagonalEnvelope(Geometry geom) - { - expandToInclude(geom); - } - - - public double getMinX() { return minX; } - public double getMaxX() { return maxX; } - public double getMinY() { return minY; } - public double getMaxY() { return maxY; } - public double getMinA() { return minA; } - public double getMaxA() { return maxA; } - public double getMinB() { return minB; } - public double getMaxB() { return maxB; } - - public boolean isNull() { return Double.isNaN(minX); } - - /** - * Sets the value of this object to the null value - */ - public void setToNull() { - minX = Double.NaN; - } - - public void expandToInclude(Geometry g) - { - g.apply(new BoundingOctagonComponentFilter()); - } - - public OctagonalEnvelope expandToInclude(CoordinateSequence seq) - { - for (int i = 0; i < seq.size(); i++) { - double x = seq.getX(i); - double y = seq.getY(i); - expandToInclude(x, y); - } - return this; - } - - public OctagonalEnvelope expandToInclude(OctagonalEnvelope oct) - { - if (oct.isNull()) return this; - - if (isNull()) { - minX = oct.minX; - maxX = oct.maxX; - minY = oct.minY; - maxY = oct.maxY; - minA = oct.minA; - maxA = oct.maxA; - minB = oct.minB; - maxB = oct.maxB; - return this; - } - if (oct.minX < minX) minX = oct.minX; - if (oct.maxX > maxX) maxX = oct.maxX; - if (oct.minY < minY) minY = oct.minY; - if (oct.maxY > maxY) maxY = oct.maxY; - if (oct.minA < minA) minA = oct.minA; - if (oct.maxA > maxA) maxA = oct.maxA; - if (oct.minB < minB) minB = oct.minB; - if (oct.maxB > maxB) maxB = oct.maxB; - return this; - } - - public OctagonalEnvelope expandToInclude(Coordinate p) - { - expandToInclude(p.x, p.y); - return this; - } - - public OctagonalEnvelope expandToInclude(Envelope env) - { - expandToInclude(env.getMinX(), env.getMinY()); - expandToInclude(env.getMinX(), env.getMaxY()); - expandToInclude(env.getMaxX(), env.getMinY()); - expandToInclude(env.getMaxX(), env.getMaxY()); - return this; - } - - public OctagonalEnvelope expandToInclude(double x, double y) - { - double A = computeA(x, y); - double B = computeB(x, y); - - if (isNull()) { - minX = x; - maxX = x; - minY = y; - maxY = y; - minA = A; - maxA = A; - minB = B; - maxB = B; - } - else { - if (x < minX) minX = x; - if (x > maxX) maxX = x; - if (y < minY) minY = y; - if (y > maxY) maxY = y; - if (A < minA) minA = A; - if (A > maxA) maxA = A; - if (B < minB) minB = B; - if (B > maxB) maxB = B; - } - return this; - } - - public void expandBy(double distance) - { - if (isNull()) return; - - double diagonalDistance = SQRT2 * distance; - - minX -= distance; - maxX += distance; - minY -= distance; - maxY += distance; - minA -= diagonalDistance; - maxA += diagonalDistance; - minB -= diagonalDistance; - maxB += diagonalDistance; - - if (! isValid()) - setToNull(); - } - - /** - * Tests if the extremal values for this octagon are valid. - * - * @return true if this object has valid values - */ - private boolean isValid() - { - if (isNull()) return true; - return minX <= maxX - && minY <= maxY - && minA <= maxA - && minB <= maxB; - } - - public boolean intersects(OctagonalEnvelope other) - { - if (isNull() || other.isNull()) { return false; } - - if (minX > other.maxX) return false; - if (maxX < other.minX) return false; - if (minY > other.maxY) return false; - if (maxY < other.minY) return false; - if (minA > other.maxA) return false; - if (maxA < other.minA) return false; - if (minB > other.maxB) return false; - if (maxB < other.minB) return false; - return true; - } - - public boolean intersects(Coordinate p) - { - if (minX > p.x) return false; - if (maxX < p.x) return false; - if (minY > p.y) return false; - if (maxY < p.y) return false; - - double A = computeA(p.x, p.y); - double B = computeB(p.x, p.y); - if (minA > A) return false; - if (maxA < A) return false; - if (minB > B) return false; - if (maxB < B) return false; - return true; - } - - public boolean contains(OctagonalEnvelope other) - { - if (isNull() || other.isNull()) { return false; } - - return other.minX >= minX - && other.maxX <= maxX - && other.minY >= minY - && other.maxY <= maxY - && other.minA >= minA - && other.maxA <= maxA - && other.minB >= minB - && other.maxB <= maxB; - } - - public Geometry toGeometry(GeometryFactory geomFactory) - { - if (isNull()) { - return geomFactory.createPoint((CoordinateSequence)null); - } - - Coordinate px00 = new Coordinate(minX, minA - minX); - Coordinate px01 = new Coordinate(minX, minX - minB); - - Coordinate px10 = new Coordinate(maxX, maxX - maxB); - Coordinate px11 = new Coordinate(maxX, maxA - maxX); - - Coordinate py00 = new Coordinate(minA - minY, minY); - Coordinate py01 = new Coordinate(minY + maxB, minY); - - Coordinate py10 = new Coordinate(maxY + minB, maxY); - Coordinate py11 = new Coordinate(maxA - maxY, maxY); - - PrecisionModel pm = geomFactory.getPrecisionModel(); - pm.makePrecise(px00); - pm.makePrecise(px01); - pm.makePrecise(px10); - pm.makePrecise(px11); - pm.makePrecise(py00); - pm.makePrecise(py01); - pm.makePrecise(py10); - pm.makePrecise(py11); - - CoordinateList coordList = new CoordinateList(); - coordList.add(px00, false); - coordList.add(px01, false); - coordList.add(py10, false); - coordList.add(py11, false); - coordList.add(px11, false); - coordList.add(px10, false); - coordList.add(py01, false); - coordList.add(py00, false); - - if (coordList.size() == 1) { - return geomFactory.createPoint(px00); - } - if (coordList.size() == 2) { - Coordinate[] pts = coordList.toCoordinateArray(); - return geomFactory.createLineString(pts); - } - // must be a polygon, so add closing point - coordList.add(px00, false); - Coordinate[] pts = coordList.toCoordinateArray(); - return geomFactory.createPolygon(geomFactory.createLinearRing(pts), null); - } - - private class BoundingOctagonComponentFilter - implements GeometryComponentFilter - { - public void filter(Geometry geom) - { - if (geom instanceof LineString) { - expandToInclude( ((LineString) geom).getCoordinateSequence()); - } - else if (geom instanceof Point) { - expandToInclude( ((Point) geom).getCoordinateSequence()); - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/Point.java b/src/main/java/com/vividsolutions/jts/geom/Point.java deleted file mode 100644 index 8a72ebf72b..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Point.java +++ /dev/null @@ -1,237 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import com.vividsolutions.jts.util.Assert; -import com.vividsolutions.jts.operation.valid.*; - -/** - * Represents a single point. - * - * A Point is topologically valid if and only if: - *

                - *
              • the coordinate which defines it (if any) is a valid coordinate - * (i.e does not have an NaN X or Y ordinate) - *
              - * - *@version 1.7 - */ -public class Point - extends Geometry - implements Puntal -{ - private static final long serialVersionUID = 4902022702746614570L; - /** - * The Coordinate wrapped by this Point. - */ - private CoordinateSequence coordinates; - - /** - * Constructs a Point with the given coordinate. - * - *@param coordinate the coordinate on which to base this Point - * , or null to create the empty geometry. - *@param precisionModel the specification of the grid of allowable points - * for this Point - *@param SRID the ID of the Spatial Reference System used by this - * Point - * @deprecated Use GeometryFactory instead - */ - public Point(Coordinate coordinate, PrecisionModel precisionModel, int SRID) { - super(new GeometryFactory(precisionModel, SRID)); - init(getFactory().getCoordinateSequenceFactory().create( - coordinate != null ? new Coordinate[]{coordinate} : new Coordinate[]{})); - } - - /** - *@param coordinates contains the single coordinate on which to base this Point - * , or null to create the empty geometry. - */ - public Point(CoordinateSequence coordinates, GeometryFactory factory) { - super(factory); - init(coordinates); - } - - private void init(CoordinateSequence coordinates) - { - if (coordinates == null) { - coordinates = getFactory().getCoordinateSequenceFactory().create(new Coordinate[]{}); - } - Assert.isTrue(coordinates.size() <= 1); - this.coordinates = coordinates; - } - - public Coordinate[] getCoordinates() { - return isEmpty() ? new Coordinate[]{} : new Coordinate[]{ - getCoordinate() - }; - } - - public int getNumPoints() { - return isEmpty() ? 0 : 1; - } - - public boolean isEmpty() { - return coordinates.size() == 0; - } - - public boolean isSimple() { - return true; - } - - public int getDimension() { - return 0; - } - - public int getBoundaryDimension() { - return Dimension.FALSE; - } - - public double getX() { - if (getCoordinate() == null) { - throw new IllegalStateException("getX called on empty Point"); - } - return getCoordinate().x; - } - - public double getY() { - if (getCoordinate() == null) { - throw new IllegalStateException("getY called on empty Point"); - } - return getCoordinate().y; - } - - public Coordinate getCoordinate() { - return coordinates.size() != 0 ? coordinates.getCoordinate(0): null; - } - - public String getGeometryType() { - return "Point"; - } - - /** - * Gets the boundary of this geometry. - * Zero-dimensional geometries have no boundary by definition, - * so an empty GeometryCollection is returned. - * - * @return an empty GeometryCollection - * @see Geometry#getBoundary - */ - public Geometry getBoundary() { - return getFactory().createGeometryCollection(null); - } - - protected Envelope computeEnvelopeInternal() { - if (isEmpty()) { - return new Envelope(); - } - Envelope env = new Envelope(); - env.expandToInclude(coordinates.getX(0), coordinates.getY(0)); - return env; - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - if (isEmpty() && other.isEmpty()) { - return true; - } - if (isEmpty() != other.isEmpty()) { - return false; - } - return equal(((Point) other).getCoordinate(), this.getCoordinate(), tolerance); - } - - public void apply(CoordinateFilter filter) { - if (isEmpty()) { return; } - filter.filter(getCoordinate()); - } - - public void apply(CoordinateSequenceFilter filter) - { - if (isEmpty()) - return; - filter.filter(coordinates, 0); - if (filter.isGeometryChanged()) - geometryChanged(); - } - - public void apply(GeometryFilter filter) { - filter.filter(this); - } - - public void apply(GeometryComponentFilter filter) { - filter.filter(this); - } - - /** - * Creates and returns a full copy of this {@link Point} object. - * (including all coordinates contained by it). - * - * @return a clone of this instance - */ - public Object clone() { - Point p = (Point) super.clone(); - p.coordinates = (CoordinateSequence) coordinates.clone(); - return p;// return the clone - } - - public Geometry reverse() - { - return (Geometry) clone(); - } - - public void normalize() - { - // a Point is always in normalized form - } - - protected int compareToSameClass(Object other) { - Point point = (Point) other; - return getCoordinate().compareTo(point.getCoordinate()); - } - - protected int compareToSameClass(Object other, CoordinateSequenceComparator comp) - { - Point point = (Point) other; - return comp.compare(this.coordinates, point.coordinates); - } - - public CoordinateSequence getCoordinateSequence() { - return coordinates; - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/Polygon.java b/src/main/java/com/vividsolutions/jts/geom/Polygon.java deleted file mode 100644 index 4b23a885c4..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Polygon.java +++ /dev/null @@ -1,450 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.util.Arrays; - -import com.vividsolutions.jts.algorithm.*; - -/** - * Represents a polygon with linear edges, which may include holes. - * The outer boundary (shell) - * and inner boundaries (holes) of the polygon are represented by {@link LinearRing}s. - * The boundary rings of the polygon may have any orientation. - * Polygons are closed, simple geometries by definition. - *

              - * The polygon model conforms to the assertions specified in the - * OpenGIS Simple Features - * Specification for SQL. - *

              - * A Polygon is topologically valid if and only if: - *

                - *
              • the coordinates which define it are valid coordinates - *
              • the linear rings for the shell and holes are valid - * (i.e. are closed and do not self-intersect) - *
              • holes touch the shell or another hole at at most one point - * (which implies that the rings of the shell and holes must not cross) - *
              • the interior of the polygon is connected, - * or equivalently no sequence of touching holes - * makes the interior of the polygon disconnected - * (i.e. effectively split the polygon into two pieces). - *
              - * - *@version 1.7 - */ -public class Polygon - extends Geometry - implements Polygonal -{ - private static final long serialVersionUID = -3494792200821764533L; - - /** - * The exterior boundary, - * or null if this Polygon - * is empty. - */ - protected LinearRing shell = null; - - /** - * The interior boundaries, if any. - * This instance var is never null. - * If there are no holes, the array is of zero length. - */ - protected LinearRing[] holes; - - /** - * Constructs a Polygon with the given exterior boundary. - * - *@param shell the outer boundary of the new Polygon, - * or null or an empty LinearRing if the empty - * geometry is to be created. - *@param precisionModel the specification of the grid of allowable points - * for this Polygon - *@param SRID the ID of the Spatial Reference System used by this - * Polygon - * @deprecated Use GeometryFactory instead - */ - public Polygon(LinearRing shell, PrecisionModel precisionModel, int SRID) { - this(shell, new LinearRing[]{}, new GeometryFactory(precisionModel, SRID)); - } - - /** - * Constructs a Polygon with the given exterior boundary and - * interior boundaries. - * - *@param shell the outer boundary of the new Polygon, - * or null or an empty LinearRing if the empty - * geometry is to be created. - *@param holes the inner boundaries of the new Polygon - * , or null or empty LinearRings if the empty - * geometry is to be created. - *@param precisionModel the specification of the grid of allowable points - * for this Polygon - *@param SRID the ID of the Spatial Reference System used by this - * Polygon - * @deprecated Use GeometryFactory instead - */ - public Polygon(LinearRing shell, LinearRing[] holes, PrecisionModel precisionModel, int SRID) { - this(shell, holes, new GeometryFactory(precisionModel, SRID)); - } - - /** - * Constructs a Polygon with the given exterior boundary and - * interior boundaries. - * - *@param shell the outer boundary of the new Polygon, - * or null or an empty LinearRing if the empty - * geometry is to be created. - *@param holes the inner boundaries of the new Polygon - * , or null or empty LinearRings if the empty - * geometry is to be created. - */ - public Polygon(LinearRing shell, LinearRing[] holes, GeometryFactory factory) { - super(factory); - if (shell == null) { - shell = getFactory().createLinearRing((CoordinateSequence)null); - } - if (holes == null) { - holes = new LinearRing[]{}; - } - if (hasNullElements(holes)) { - throw new IllegalArgumentException("holes must not contain null elements"); - } - if (shell.isEmpty() && hasNonEmptyElements(holes)) { - throw new IllegalArgumentException("shell is empty but holes are not"); - } - this.shell = shell; - this.holes = holes; - } - - public Coordinate getCoordinate() { - return shell.getCoordinate(); - } - - public Coordinate[] getCoordinates() { - if (isEmpty()) { - return new Coordinate[]{}; - } - Coordinate[] coordinates = new Coordinate[getNumPoints()]; - int k = -1; - Coordinate[] shellCoordinates = shell.getCoordinates(); - for (int x = 0; x < shellCoordinates.length; x++) { - k++; - coordinates[k] = shellCoordinates[x]; - } - for (int i = 0; i < holes.length; i++) { - Coordinate[] childCoordinates = holes[i].getCoordinates(); - for (int j = 0; j < childCoordinates.length; j++) { - k++; - coordinates[k] = childCoordinates[j]; - } - } - return coordinates; - } - - public int getNumPoints() { - int numPoints = shell.getNumPoints(); - for (int i = 0; i < holes.length; i++) { - numPoints += holes[i].getNumPoints(); - } - return numPoints; - } - - public int getDimension() { - return 2; - } - - public int getBoundaryDimension() { - return 1; - } - - public boolean isEmpty() { - return shell.isEmpty(); - } - - /** - * Tests if a valid polygon is simple. - * This method always returns true, since a valid polygon is always simple - * - * @return true - */ - /* - public boolean isSimple() { - return true; - } -*/ - - public boolean isRectangle() - { - if (getNumInteriorRing() != 0) return false; - if (shell == null) return false; - if (shell.getNumPoints() != 5) return false; - - CoordinateSequence seq = shell.getCoordinateSequence(); - - // check vertices have correct values - Envelope env = getEnvelopeInternal(); - for (int i = 0; i < 5; i++) { - double x = seq.getX(i); - if (! (x == env.getMinX() || x == env.getMaxX())) return false; - double y = seq.getY(i); - if (! (y == env.getMinY() || y == env.getMaxY())) return false; - } - - // check vertices are in right order - double prevX = seq.getX(0); - double prevY = seq.getY(0); - for (int i = 1; i <= 4; i++) { - double x = seq.getX(i); - double y = seq.getY(i); - boolean xChanged = x != prevX; - boolean yChanged = y != prevY; - if (xChanged == yChanged) - return false; - prevX = x; - prevY = y; - } - return true; - } - - public LineString getExteriorRing() { - return shell; - } - - public int getNumInteriorRing() { - return holes.length; - } - - public LineString getInteriorRingN(int n) { - return holes[n]; - } - - public String getGeometryType() { - return "Polygon"; - } - - /** - * Returns the area of this Polygon - * - *@return the area of the polygon - */ - public double getArea() - { - double area = 0.0; - area += Math.abs(CGAlgorithms.signedArea(shell.getCoordinateSequence())); - for (int i = 0; i < holes.length; i++) { - area -= Math.abs(CGAlgorithms.signedArea(holes[i].getCoordinateSequence())); - } - return area; - } - - /** - * Returns the perimeter of this Polygon - * - *@return the perimeter of the polygon - */ - public double getLength() - { - double len = 0.0; - len += shell.getLength(); - for (int i = 0; i < holes.length; i++) { - len += holes[i].getLength(); - } - return len; - } - - /** - * Computes the boundary of this geometry - * - * @return a lineal geometry (which may be empty) - * @see Geometry#getBoundary - */ - public Geometry getBoundary() { - if (isEmpty()) { - return getFactory().createMultiLineString(null); - } - LinearRing[] rings = new LinearRing[holes.length + 1]; - rings[0] = shell; - for (int i = 0; i < holes.length; i++) { - rings[i + 1] = holes[i]; - } - // create LineString or MultiLineString as appropriate - if (rings.length <= 1) - return getFactory().createLinearRing(rings[0].getCoordinateSequence()); - return getFactory().createMultiLineString(rings); - } - - protected Envelope computeEnvelopeInternal() { - return shell.getEnvelopeInternal(); - } - - public boolean equalsExact(Geometry other, double tolerance) { - if (!isEquivalentClass(other)) { - return false; - } - Polygon otherPolygon = (Polygon) other; - Geometry thisShell = shell; - Geometry otherPolygonShell = otherPolygon.shell; - if (!thisShell.equalsExact(otherPolygonShell, tolerance)) { - return false; - } - if (holes.length != otherPolygon.holes.length) { - return false; - } - for (int i = 0; i < holes.length; i++) { - if (!((Geometry) holes[i]).equalsExact(otherPolygon.holes[i], tolerance)) { - return false; - } - } - return true; - } - - public void apply(CoordinateFilter filter) { - shell.apply(filter); - for (int i = 0; i < holes.length; i++) { - holes[i].apply(filter); - } - } - - public void apply(CoordinateSequenceFilter filter) - { - shell.apply(filter); - if (! filter.isDone()) { - for (int i = 0; i < holes.length; i++) { - holes[i].apply(filter); - if (filter.isDone()) - break; - } - } - if (filter.isGeometryChanged()) - geometryChanged(); - } - - public void apply(GeometryFilter filter) { - filter.filter(this); - } - - public void apply(GeometryComponentFilter filter) { - filter.filter(this); - shell.apply(filter); - for (int i = 0; i < holes.length; i++) { - holes[i].apply(filter); - } - } - - /** - * Creates and returns a full copy of this {@link Polygon} object. - * (including all coordinates contained by it). - * - * @return a clone of this instance - */ - public Object clone() { - Polygon poly = (Polygon) super.clone(); - poly.shell = (LinearRing) shell.clone(); - poly.holes = new LinearRing[holes.length]; - for (int i = 0; i < holes.length; i++) { - poly.holes[i] = (LinearRing) holes[i].clone(); - } - return poly;// return the clone - } - - public Geometry convexHull() { - return getExteriorRing().convexHull(); - } - - public void normalize() { - normalize(shell, true); - for (int i = 0; i < holes.length; i++) { - normalize(holes[i], false); - } - Arrays.sort(holes); - } - - protected int compareToSameClass(Object o) { - LinearRing thisShell = shell; - LinearRing otherShell = ((Polygon) o).shell; - return thisShell.compareToSameClass(otherShell); - } - - protected int compareToSameClass(Object o, CoordinateSequenceComparator comp) { - Polygon poly = (Polygon) o; - - LinearRing thisShell = shell; - LinearRing otherShell = poly.shell; - int shellComp = thisShell.compareToSameClass(otherShell, comp); - if (shellComp != 0) return shellComp; - - int nHole1 = getNumInteriorRing(); - int nHole2 = poly.getNumInteriorRing(); - int i = 0; - while (i < nHole1 && i < nHole2) { - LinearRing thisHole = (LinearRing) getInteriorRingN(i); - LinearRing otherHole = (LinearRing) poly.getInteriorRingN(i); - int holeComp = thisHole.compareToSameClass(otherHole, comp); - if (holeComp != 0) return holeComp; - i++; - } - if (i < nHole1) return 1; - if (i < nHole2) return -1; - return 0; - } - - private void normalize(LinearRing ring, boolean clockwise) { - if (ring.isEmpty()) { - return; - } - Coordinate[] uniqueCoordinates = new Coordinate[ring.getCoordinates().length - 1]; - System.arraycopy(ring.getCoordinates(), 0, uniqueCoordinates, 0, uniqueCoordinates.length); - Coordinate minCoordinate = CoordinateArrays.minCoordinate(ring.getCoordinates()); - CoordinateArrays.scroll(uniqueCoordinates, minCoordinate); - System.arraycopy(uniqueCoordinates, 0, ring.getCoordinates(), 0, uniqueCoordinates.length); - ring.getCoordinates()[uniqueCoordinates.length] = uniqueCoordinates[0]; - if (CGAlgorithms.isCCW(ring.getCoordinates()) == clockwise) { - CoordinateArrays.reverse(ring.getCoordinates()); - } - } - - public Geometry reverse() - { - Polygon poly = (Polygon) super.clone(); - poly.shell = (LinearRing) ((LinearRing) shell.clone()).reverse(); - poly.holes = new LinearRing[holes.length]; - for (int i = 0; i < holes.length; i++) { - poly.holes[i] = (LinearRing) ((LinearRing) holes[i].clone()).reverse(); - } - return poly;// return the clone - } -} - diff --git a/src/main/java/com/vividsolutions/jts/geom/Polygonal.java b/src/main/java/com/vividsolutions/jts/geom/Polygonal.java deleted file mode 100644 index 28f302148e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Polygonal.java +++ /dev/null @@ -1,47 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom; - -/** - * Identifies {@link Geometry} subclasses which - * are 2-dimensional - * and have components which have {@link Lineal} boundaries. - * - * @author Martin Davis - * - */ -public interface Polygonal -{ - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/PrecisionModel.java b/src/main/java/com/vividsolutions/jts/geom/PrecisionModel.java deleted file mode 100644 index 0bd3266d18..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/PrecisionModel.java +++ /dev/null @@ -1,488 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * Specifies the precision model of the {@link Coordinate}s in a {@link Geometry}. - * In other words, specifies the grid of allowable - * points for all Geometrys. - *

              - * The {@link #makePrecise(Coordinate)} method allows rounding a coordinate to - * a "precise" value; that is, one whose - * precision is known exactly. - *

              - * Coordinates are assumed to be precise in geometries. - * That is, the coordinates are assumed to be rounded to the - * precision model given for the geometry. - * JTS input routines automatically round coordinates to the precision model - * before creating Geometries. - * All internal operations - * assume that coordinates are rounded to the precision model. - * Constructive methods (such as boolean operations) always round computed - * coordinates to the appropriate precision model. - *

              - * Currently three types of precision model are supported: - *

                - *
              • FLOATING - represents full double precision floating point. - * This is the default precision model used in JTS - *
              • FLOATING_SINGLE - represents single precision floating point. - *
              • FIXED - represents a model with a fixed number of decimal places. - * A Fixed Precision Model is specified by a scale factor. - * The scale factor specifies the size of the grid which numbers are rounded to. - * Input coordinates are mapped to fixed coordinates according to the following - * equations: - *
                  - *
                • jtsPt.x = round( (inputPt.x * scale ) / scale - *
                • jtsPt.y = round( (inputPt.y * scale ) / scale - *
                - *
              - * For example, to specify 3 decimal places of precision, use a scale factor - * of 1000. To specify -3 decimal places of precision (i.e. rounding to - * the nearest 1000), use a scale factor of 0.001. - *

              - * Coordinates are represented internally as Java double-precision values. - * Since Java uses the IEEE-394 floating point standard, this - * provides 53 bits of precision. (Thus the maximum precisely representable - * integer is 9,007,199,254,740,992 - or almost 16 decimal digits of precision). - *

              - * JTS binary methods currently do not handle inputs which have different precision models. - * The precision model of any constructed geometric value is undefined. - * - *@version 1.7 - */ -public class PrecisionModel implements Serializable, Comparable -{ - /** - * Determines which of two {@link PrecisionModel}s is the most precise - * (allows the greatest number of significant digits). - * - * @param pm1 a PrecisionModel - * @param pm2 a PrecisionModel - * @return the PrecisionModel which is most precise - */ - public static PrecisionModel mostPrecise(PrecisionModel pm1, PrecisionModel pm2) - { - if (pm1.compareTo(pm2) >= 0) - return pm1; - return pm2; - } - - private static final long serialVersionUID = 7777263578777803835L; - - /** - * The types of Precision Model which JTS supports. - */ - public static class Type - implements Serializable - { - private static final long serialVersionUID = -5528602631731589822L; - private static Map nameToTypeMap = new HashMap(); - public Type(String name) { - this.name = name; - nameToTypeMap.put(name, this); - } - private String name; - public String toString() { return name; } - - - /* - * Ssee http://www.javaworld.com/javaworld/javatips/jw-javatip122.html - */ - private Object readResolve() { - return nameToTypeMap.get(name); - } - } - - /** - * Fixed Precision indicates that coordinates have a fixed number of decimal places. - * The number of decimal places is determined by the log10 of the scale factor. - */ - public static final Type FIXED = new Type("FIXED"); - /** - * Floating precision corresponds to the standard Java - * double-precision floating-point representation, which is - * based on the IEEE-754 standard - */ - public static final Type FLOATING = new Type("FLOATING"); - /** - * Floating single precision corresponds to the standard Java - * single-precision floating-point representation, which is - * based on the IEEE-754 standard - */ - public static final Type FLOATING_SINGLE = new Type("FLOATING SINGLE"); - - - /** - * The maximum precise value representable in a double. Since IEE754 - * double-precision numbers allow 53 bits of mantissa, the value is equal to - * 2^53 - 1. This provides almost 16 decimal digits of precision. - */ - public final static double maximumPreciseValue = 9007199254740992.0; - - /** - * The type of PrecisionModel this represents. - */ - private Type modelType; - /** - * The scale factor which determines the number of decimal places in fixed precision. - */ - private double scale; - - /** - * Creates a PrecisionModel with a default precision - * of FLOATING. - */ - public PrecisionModel() { - // default is floating precision - modelType = FLOATING; - } - - /** - * Creates a PrecisionModel that specifies - * an explicit precision model type. - * If the model type is FIXED the scale factor will default to 1. - * - * @param modelType the type of the precision model - */ - public PrecisionModel(Type modelType) - { - this.modelType = modelType; - if (modelType == FIXED) - { - setScale(1.0); - } - } - /** - * Creates a PrecisionModel that specifies Fixed precision. - * Fixed-precision coordinates are represented as precise internal coordinates, - * which are rounded to the grid defined by the scale factor. - * - *@param scale amount by which to multiply a coordinate after subtracting - * the offset, to obtain a precise coordinate - *@param offsetX not used. - *@param offsetY not used. - * - * @deprecated offsets are no longer supported, since internal representation is rounded floating point - */ - public PrecisionModel(double scale, double offsetX, double offsetY) { - modelType = FIXED; - setScale(scale); - } - /** - * Creates a PrecisionModel that specifies Fixed precision. - * Fixed-precision coordinates are represented as precise internal coordinates, - * which are rounded to the grid defined by the scale factor. - * - *@param scale amount by which to multiply a coordinate after subtracting - * the offset, to obtain a precise coordinate - */ - public PrecisionModel(double scale) { - modelType = FIXED; - setScale(scale); - } - /** - * Copy constructor to create a new PrecisionModel - * from an existing one. - */ - public PrecisionModel(PrecisionModel pm) { - modelType = pm.modelType; - scale = pm.scale; - } - - - /** - * Tests whether the precision model supports floating point - * @return true if the precision model supports floating point - */ - public boolean isFloating() - { - return modelType == FLOATING || modelType == FLOATING_SINGLE; - } - - /** - * Returns the maximum number of significant digits provided by this - * precision model. - * Intended for use by routines which need to print out - * decimal representations of precise values (such as {@link WKTWriter}). - *

              - * This method would be more correctly called - * getMinimumDecimalPlaces, - * since it actually computes the number of decimal places - * that is required to correctly display the full - * precision of an ordinate value. - *

              - * Since it is difficult to compute the required number of - * decimal places for scale factors which are not powers of 10, - * the algorithm uses a very rough approximation in this case. - * This has the side effect that for scale factors which are - * powers of 10 the value returned is 1 greater than the true value. - * - * - * @return the maximum number of decimal places provided by this precision model - */ - public int getMaximumSignificantDigits() { - int maxSigDigits = 16; - if (modelType == FLOATING) { - maxSigDigits = 16; - } else if (modelType == FLOATING_SINGLE) { - maxSigDigits = 6; - } else if (modelType == FIXED) { - maxSigDigits = 1 + (int) Math.ceil(Math.log(getScale()) / Math.log(10)); - } - return maxSigDigits; - } - - /** - * Returns the scale factor used to specify a fixed precision model. - * The number of decimal places of precision is - * equal to the base-10 logarithm of the scale factor. - * Non-integral and negative scale factors are supported. - * Negative scale factors indicate that the places - * of precision is to the left of the decimal point. - * - *@return the scale factor for the fixed precision model - */ - public double getScale() { - return scale; - } - - /** - * Gets the type of this precision model - * @return the type of this precision model - * @see Type - */ - public Type getType() - { - return modelType; - } - /** - * Sets the multiplying factor used to obtain a precise coordinate. - * This method is private because PrecisionModel is an immutable (value) type. - */ - private void setScale(double scale) - { - this.scale = Math.abs(scale); - } - - /** - * Returns the x-offset used to obtain a precise coordinate. - * - * @return the amount by which to subtract the x-coordinate before - * multiplying by the scale - * @deprecated Offsets are no longer used - */ - public double getOffsetX() { - //We actually don't use offsetX and offsetY anymore ... [Jon Aquino] - return 0; - } - - - - /** - * Returns the y-offset used to obtain a precise coordinate. - * - * @return the amount by which to subtract the y-coordinate before - * multiplying by the scale - * @deprecated Offsets are no longer used - */ - public double getOffsetY() { - return 0; - } - - /** - * Sets internal to the precise representation of external. - * - * @param external the original coordinate - * @param internal the coordinate whose values will be changed to the - * precise representation of external - * @deprecated use makePrecise instead - */ - public void toInternal (Coordinate external, Coordinate internal) { - if (isFloating()) { - internal.x = external.x; - internal.y = external.y; - } - else { - internal.x = makePrecise(external.x); - internal.y = makePrecise(external.y); - } - internal.z = external.z; - } - - /** - * Returns the precise representation of external. - * - *@param external the original coordinate - *@return the coordinate whose values will be changed to the precise - * representation of external - * @deprecated use makePrecise instead - */ - public Coordinate toInternal(Coordinate external) { - Coordinate internal = new Coordinate(external); - makePrecise(internal); - return internal; - } - - /** - * Returns the external representation of internal. - * - *@param internal the original coordinate - *@return the coordinate whose values will be changed to the - * external representation of internal - * @deprecated no longer needed, since internal representation is same as external representation - */ - public Coordinate toExternal(Coordinate internal) { - Coordinate external = new Coordinate(internal); - return external; - } - - /** - * Sets external to the external representation of internal. - * - *@param internal the original coordinate - *@param external the coordinate whose values will be changed to the - * external representation of internal - * @deprecated no longer needed, since internal representation is same as external representation - */ - public void toExternal(Coordinate internal, Coordinate external) { - external.x = internal.x; - external.y = internal.y; - } - - /** - * Rounds a numeric value to the PrecisionModel grid. - * Asymmetric Arithmetic Rounding is used, to provide - * uniform rounding behaviour no matter where the number is - * on the number line. - *

              - * This method has no effect on NaN values. - *

              - * Note: Java's Math#rint uses the "Banker's Rounding" algorithm, - * which is not suitable for precision operations elsewhere in JTS. - */ - public double makePrecise(double val) - { - // don't change NaN values - if (Double.isNaN(val)) return val; - - if (modelType == FLOATING_SINGLE) { - float floatSingleVal = (float) val; - return (double) floatSingleVal; - } - if (modelType == FIXED) { - return Math.round(val * scale) / scale; -// return Math.rint(val * scale) / scale; - } - // modelType == FLOATING - no rounding necessary - return val; - } - - /** - * Rounds a Coordinate to the PrecisionModel grid. - */ - public void makePrecise(Coordinate coord) - { - // optimization for full precision - if (modelType == FLOATING) return; - - coord.x = makePrecise(coord.x); - coord.y = makePrecise(coord.y); - //MD says it's OK that we're not makePrecise'ing the z [Jon Aquino] - } - - - public String toString() { - String description = "UNKNOWN"; - if (modelType == FLOATING) { - description = "Floating"; - } else if (modelType == FLOATING_SINGLE) { - description = "Floating-Single"; - } else if (modelType == FIXED) { - description = "Fixed (Scale=" + getScale() + ")"; - } - return description; - } - - public boolean equals(Object other) { - if (! (other instanceof PrecisionModel)) { - return false; - } - PrecisionModel otherPrecisionModel = (PrecisionModel) other; - return modelType == otherPrecisionModel.modelType - && scale == otherPrecisionModel.scale; - } - /** - * Compares this {@link PrecisionModel} object with the specified object for order. - * A PrecisionModel is greater than another if it provides greater precision. - * The comparison is based on the value returned by the - * {@link #getMaximumSignificantDigits} method. - * This comparison is not strictly accurate when comparing floating precision models - * to fixed models; however, it is correct when both models are either floating or fixed. - * - *@param o the PrecisionModel with which this PrecisionModel - * is being compared - *@return a negative integer, zero, or a positive integer as this PrecisionModel - * is less than, equal to, or greater than the specified PrecisionModel - */ - public int compareTo(Object o) { - PrecisionModel other = (PrecisionModel) o; - - int sigDigits = getMaximumSignificantDigits(); - int otherSigDigits = other.getMaximumSignificantDigits(); - return (new Integer(sigDigits)).compareTo(new Integer(otherSigDigits)); -// if (sigDigits > otherSigDigits) -// return 1; -// else if -// if (modelType == FLOATING && other.modelType == FLOATING) return 0; -// if (modelType == FLOATING && other.modelType != FLOATING) return 1; -// if (modelType != FLOATING && other.modelType == FLOATING) return -1; -// if (modelType == FIXED && other.modelType == FIXED) { -// if (scale > other.scale) -// return 1; -// else if (scale < other.scale) -// return -1; -// else -// return 0; -// } -// Assert.shouldNeverReachHere("Unknown Precision Model type encountered"); -// return 0; - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/geom/Puntal.java b/src/main/java/com/vividsolutions/jts/geom/Puntal.java deleted file mode 100644 index 518889fd5c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Puntal.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom; - -/** - * Identifies {@link Geometry} subclasses which - * are 0-dimensional and with components which are {@link Point}s. - * - * @author Martin Davis - * - */ -public interface Puntal { - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/TopologyException.java b/src/main/java/com/vividsolutions/jts/geom/TopologyException.java deleted file mode 100644 index d8bb85114e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/TopologyException.java +++ /dev/null @@ -1,68 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -/** - * Indicates an invalid or inconsistent topological situation encountered during processing - * - * @version 1.7 - */ -public class TopologyException - extends RuntimeException -{ - private static String msgWithCoord(String msg, Coordinate pt) - { - if (pt != null) - return msg + " [ " + pt + " ]"; - return msg; - } - - private Coordinate pt = null; - - public TopologyException(String msg) - { - super(msg); - } - - public TopologyException(String msg, Coordinate pt) - { - super(msgWithCoord(msg, pt)); - this.pt = new Coordinate(pt); - } - - public Coordinate getCoordinate() { return pt; } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/Triangle.java b/src/main/java/com/vividsolutions/jts/geom/Triangle.java deleted file mode 100644 index 6c537c466f..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/Triangle.java +++ /dev/null @@ -1,578 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom; - -import com.vividsolutions.jts.algorithm.*; - -/** - * Represents a planar triangle, and provides methods for calculating various - * properties of triangles. - * - * @version 1.7 - */ -public class Triangle -{ - - /** - * Tests whether a triangle is acute. A triangle is acute iff all interior - * angles are acute. This is a strict test - right triangles will return - * false A triangle which is not acute is either right or obtuse. - *

              - * Note: this implementation is not robust for angles very close to 90 - * degrees. - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return true if the triangle is acute - */ - public static boolean isAcute(Coordinate a, Coordinate b, Coordinate c) - { - if (!Angle.isAcute(a, b, c)) - return false; - if (!Angle.isAcute(b, c, a)) - return false; - if (!Angle.isAcute(c, a, b)) - return false; - return true; - } - - /** - * Computes the line which is the perpendicular bisector of the line segment - * a-b. - * - * @param a - * a point - * @param b - * another point - * @return the perpendicular bisector, as an HCoordinate - */ - public static HCoordinate perpendicularBisector(Coordinate a, Coordinate b) - { - // returns the perpendicular bisector of the line segment ab - double dx = b.x - a.x; - double dy = b.y - a.y; - HCoordinate l1 = new HCoordinate(a.x + dx / 2.0, a.y + dy / 2.0, 1.0); - HCoordinate l2 = new HCoordinate(a.x - dy + dx / 2.0, a.y + dx + dy / 2.0, - 1.0); - return new HCoordinate(l1, l2); - } - - /** - * Computes the circumcentre of a triangle. The circumcentre is the centre of - * the circumcircle, the smallest circle which encloses the triangle. It is - * also the common intersection point of the perpendicular bisectors of the - * sides of the triangle, and is the only point which has equal distance to - * all three vertices of the triangle. - * - * @param a - * a vertx of the triangle - * @param b - * a vertx of the triangle - * @param c - * a vertx of the triangle - * @return the circumcentre of the triangle - */ - /* - * // original non-robust algorithm public static Coordinate - * circumcentre(Coordinate a, Coordinate b, Coordinate c) { // compute the - * perpendicular bisector of chord ab HCoordinate cab = - * perpendicularBisector(a, b); // compute the perpendicular bisector of chord - * bc HCoordinate cbc = perpendicularBisector(b, c); // compute the - * intersection of the bisectors (circle radii) HCoordinate hcc = new - * HCoordinate(cab, cbc); Coordinate cc = null; try { cc = new - * Coordinate(hcc.getX(), hcc.getY()); } catch (NotRepresentableException ex) - * { // MD - not sure what we can do to prevent this (robustness problem) // - * Idea - can we condition which edges we choose? throw new - * IllegalStateException(ex.getMessage()); } - * - * //System.out.println("Acc = " + a.distance(cc) + ", Bcc = " + - * b.distance(cc) + ", Ccc = " + c.distance(cc) ); - * - * return cc; } - */ - - /** - * Computes the circumcentre of a triangle. The circumcentre is the centre of - * the circumcircle, the smallest circle which encloses the triangle. It is - * also the common intersection point of the perpendicular bisectors of the - * sides of the triangle, and is the only point which has equal distance to - * all three vertices of the triangle. - *

              - * The circumcentre does not necessarily lie within the triangle. For example, - * the circumcentre of an obtuse isoceles triangle lies outside the triangle. - *

              - * This method uses an algorithm due to J.R.Shewchuk which uses normalization - * to the origin to improve the accuracy of computation. (See Lecture Notes - * on Geometric Robustness, Jonathan Richard Shewchuk, 1999). - * - * @param a - * a vertx of the triangle - * @param b - * a vertx of the triangle - * @param c - * a vertx of the triangle - * @return the circumcentre of the triangle - */ - public static Coordinate circumcentre(Coordinate a, Coordinate b, Coordinate c) - { - double cx = c.x; - double cy = c.y; - double ax = a.x - cx; - double ay = a.y - cy; - double bx = b.x - cx; - double by = b.y - cy; - - double denom = 2 * det(ax, ay, bx, by); - double numx = det(ay, ax * ax + ay * ay, by, bx * bx + by * by); - double numy = det(ax, ax * ax + ay * ay, bx, bx * bx + by * by); - - double ccx = cx - numx / denom; - double ccy = cy + numy / denom; - - return new Coordinate(ccx, ccy); - } - - /** - * Computes the determinant of a 2x2 matrix. Uses standard double-precision - * arithmetic, so is susceptible to round-off error. - * - * @param m00 - * the [0,0] entry of the matrix - * @param m01 - * the [0,1] entry of the matrix - * @param m10 - * the [1,0] entry of the matrix - * @param m11 - * the [1,1] entry of the matrix - * @return the determinant - */ - private static double det(double m00, double m01, double m10, double m11) - { - return m00 * m11 - m01 * m10; - } - - /** - * Computes the incentre of a triangle. The inCentre of a triangle is - * the point which is equidistant from the sides of the triangle. It is also - * the point at which the bisectors of the triangle's angles meet. It is the - * centre of the triangle's incircle, which is the unique circle that - * is tangent to each of the triangle's three sides. - *

              - * The incentre always lies within the triangle. - * - * @param a - * a vertx of the triangle - * @param b - * a vertx of the triangle - * @param c - * a vertx of the triangle - * @return the point which is the incentre of the triangle - */ - public static Coordinate inCentre(Coordinate a, Coordinate b, Coordinate c) - { - // the lengths of the sides, labelled by their opposite vertex - double len0 = b.distance(c); - double len1 = a.distance(c); - double len2 = a.distance(b); - double circum = len0 + len1 + len2; - - double inCentreX = (len0 * a.x + len1 * b.x + len2 * c.x) / circum; - double inCentreY = (len0 * a.y + len1 * b.y + len2 * c.y) / circum; - return new Coordinate(inCentreX, inCentreY); - } - - /** - * Computes the centroid (centre of mass) of a triangle. This is also the - * point at which the triangle's three medians intersect (a triangle median is - * the segment from a vertex of the triangle to the midpoint of the opposite - * side). The centroid divides each median in a ratio of 2:1. - *

              - * The centroid always lies within the triangle. - * - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the centroid of the triangle - */ - public static Coordinate centroid(Coordinate a, Coordinate b, Coordinate c) - { - double x = (a.x + b.x + c.x) / 3; - double y = (a.y + b.y + c.y) / 3; - return new Coordinate(x, y); - } - - /** - * Computes the length of the longest side of a triangle - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the length of the longest side of the triangle - */ - public static double longestSideLength(Coordinate a, Coordinate b, - Coordinate c) - { - double lenAB = a.distance(b); - double lenBC = b.distance(c); - double lenCA = c.distance(a); - double maxLen = lenAB; - if (lenBC > maxLen) - maxLen = lenBC; - if (lenCA > maxLen) - maxLen = lenCA; - return maxLen; - } - - /** - * Computes the point at which the bisector of the angle ABC cuts the segment - * AC. - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the angle bisector cut point - */ - public static Coordinate angleBisector(Coordinate a, Coordinate b, - Coordinate c) - { - /** - * Uses the fact that the lengths of the parts of the split segment are - * proportional to the lengths of the adjacent triangle sides - */ - double len0 = b.distance(a); - double len2 = b.distance(c); - double frac = len0 / (len0 + len2); - double dx = c.x - a.x; - double dy = c.y - a.y; - - Coordinate splitPt = new Coordinate(a.x + frac * dx, a.y + frac * dy); - return splitPt; - } - - /** - * Computes the 2D area of a triangle. The area value is always non-negative. - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the area of the triangle - * - * @see #signedArea(Coordinate, Coordinate, Coordinate) - */ - public static double area(Coordinate a, Coordinate b, Coordinate c) - { - return Math - .abs(((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2); - } - - /** - * Computes the signed 2D area of a triangle. The area value is positive if - * the triangle is oriented CW, and negative if it is oriented CCW. - *

              - * The signed area value can be used to determine point orientation, but the - * implementation in this method is susceptible to round-off errors. Use - * {@link CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate)} - * for robust orientation calculation. - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the signed 2D area of the triangle - * - * @see CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate) - */ - public static double signedArea(Coordinate a, Coordinate b, Coordinate c) - { - /** - * Uses the formula 1/2 * | u x v | where u,v are the side vectors of the - * triangle x is the vector cross-product For 2D vectors, this formual - * simplifies to the expression below - */ - return ((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2; - } - - /** - * Computes the 3D area of a triangle. The value computed is alway - * non-negative. - * - * @param a - * a vertex of the triangle - * @param b - * a vertex of the triangle - * @param c - * a vertex of the triangle - * @return the 3D area of the triangle - */ - public static double area3D(Coordinate a, Coordinate b, Coordinate c) - { - /** - * Uses the formula 1/2 * | u x v | where u,v are the side vectors of the - * triangle x is the vector cross-product - */ - // side vectors u and v - double ux = b.x - a.x; - double uy = b.y - a.y; - double uz = b.z - a.z; - - double vx = c.x - a.x; - double vy = c.y - a.y; - double vz = c.z - a.z; - - // cross-product = u x v - double crossx = uy * vz - uz * vy; - double crossy = uz * vx - ux * vz; - double crossz = ux * vy - uy * vx; - - // tri area = 1/2 * | u x v | - double absSq = crossx * crossx + crossy * crossy + crossz * crossz; - double area3D = Math.sqrt(absSq) / 2; - - return area3D; - } - - /** - * Computes the Z-value (elevation) of an XY point on a three-dimensional - * plane defined by a triangle whose vertices have Z-values. The defining - * triangle must not be degenerate (in other words, the triangle must enclose - * a non-zero area), and must not be parallel to the Z-axis. - *

              - * This method can be used to interpolate the Z-value of a point inside a - * triangle (for example, of a TIN facet with elevations on the vertices). - * - * @param p - * the point to compute the Z-value of - * @param v0 - * a vertex of a triangle, with a Z ordinate - * @param v1 - * a vertex of a triangle, with a Z ordinate - * @param v2 - * a vertex of a triangle, with a Z ordinate - * @return the computed Z-value (elevation) of the point - */ - public static double interpolateZ(Coordinate p, Coordinate v0, Coordinate v1, - Coordinate v2) - { - double x0 = v0.x; - double y0 = v0.y; - double a = v1.x - x0; - double b = v2.x - x0; - double c = v1.y - y0; - double d = v2.y - y0; - double det = a * d - b * c; - double dx = p.x - x0; - double dy = p.y - y0; - double t = (d * dx - b * dy) / det; - double u = (-c * dx + a * dy) / det; - double z = v0.z + t * (v1.z - v0.z) + u * (v2.z - v0.z); - return z; - } - - /** - * The coordinates of the vertices of the triangle - */ - public Coordinate p0, p1, p2; - - /** - * Creates a new triangle with the given vertices. - * - * @param p0 - * a vertex - * @param p1 - * a vertex - * @param p2 - * a vertex - */ - public Triangle(Coordinate p0, Coordinate p1, Coordinate p2) - { - this.p0 = p0; - this.p1 = p1; - this.p2 = p2; - } - - /** - * Computes the incentre of this triangle. The incentre of a triangle - * is the point which is equidistant from the sides of the triangle. It is - * also the point at which the bisectors of the triangle's angles meet. It is - * the centre of the triangle's incircle, which is the unique circle - * that is tangent to each of the triangle's three sides. - * - * @return the point which is the inCentre of this triangle - */ - public Coordinate inCentre() - { - return inCentre(p0, p1, p2); - } - - /** - * Tests whether this triangle is acute. A triangle is acute iff all interior - * angles are acute. This is a strict test - right triangles will return - * false A triangle which is not acute is either right or obtuse. - *

              - * Note: this implementation is not robust for angles very close to 90 - * degrees. - * - * @return true if this triangle is acute - */ - public boolean isAcute() - { - return isAcute(this.p0, this.p1, this.p2); - } - - /** - * Computes the circumcentre of this triangle. The circumcentre is the centre - * of the circumcircle, the smallest circle which encloses the triangle. It is - * also the common intersection point of the perpendicular bisectors of the - * sides of the triangle, and is the only point which has equal distance to - * all three vertices of the triangle. - *

              - * The circumcentre does not necessarily lie within the triangle. - *

              - * This method uses an algorithm due to J.R.Shewchuk which uses normalization - * to the origin to improve the accuracy of computation. (See Lecture Notes - * on Geometric Robustness, Jonathan Richard Shewchuk, 1999). - * - * @return the circumcentre of this triangle - */ - public Coordinate circumcentre() - { - return circumcentre(this.p0, this.p1, this.p2); - } - - /** - * Computes the centroid (centre of mass) of this triangle. This is also the - * point at which the triangle's three medians intersect (a triangle median is - * the segment from a vertex of the triangle to the midpoint of the opposite - * side). The centroid divides each median in a ratio of 2:1. - *

              - * The centroid always lies within the triangle. - * - * @return the centroid of this triangle - */ - public Coordinate centroid() - { - return centroid(this.p0, this.p1, this.p2); - } - - /** - * Computes the length of the longest side of this triangle - * - * @return the length of the longest side of this triangle - */ - public double longestSideLength() - { - return longestSideLength(this.p0, this.p1, this.p2); - } - - /** - * Computes the 2D area of this triangle. The area value is always - * non-negative. - * - * @return the area of this triangle - * - * @see #signedArea() - */ - public double area() - { - return area(this.p0, this.p1, this.p2); - } - - /** - * Computes the signed 2D area of this triangle. The area value is positive if - * the triangle is oriented CW, and negative if it is oriented CCW. - *

              - * The signed area value can be used to determine point orientation, but the - * implementation in this method is susceptible to round-off errors. Use - * {@link CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate)} - * for robust orientation calculation. - * - * @return the signed 2D area of this triangle - * - * @see CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate) - */ - public double signedArea() - { - return signedArea(this.p0, this.p1, this.p2); - } - - /** - * Computes the 3D area of this triangle. The value computed is alway - * non-negative. - * - * @return the 3D area of this triangle - */ - public double area3D() - { - return area3D(this.p0, this.p1, this.p2); - } - - /** - * Computes the Z-value (elevation) of an XY point on a three-dimensional - * plane defined by this triangle (whose vertices must have Z-values). This - * triangle must not be degenerate (in other words, the triangle must enclose - * a non-zero area), and must not be parallel to the Z-axis. - *

              - * This method can be used to interpolate the Z-value of a point inside this - * triangle (for example, of a TIN facet with elevations on the vertices). - * - * @param p - * the point to compute the Z-value of - * @return the computed Z-value (elevation) of the point - */ - public double interpolateZ(Coordinate p) - { - if (p == null) - throw new IllegalArgumentException("Supplied point is null."); - return interpolateZ(p, this.p0, this.p1, this.p2); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java b/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java deleted file mode 100644 index 84b4f1a6aa..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java +++ /dev/null @@ -1,281 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.impl; - -import java.io.Serializable; -import com.vividsolutions.jts.geom.*; - -/** - * A {@link CoordinateSequence} backed by an array of {@link Coordinates}. - * This is the implementation that {@link Geometry}s use by default. - * Coordinates returned by #toArray and #getCoordinate are live -- - * modifications to them are actually changing the - * CoordinateSequence's underlying data. - * A dimension may be specified for the coordinates in the sequence, - * which may be 2 or 3. - * The actual coordinates will always have 3 ordinates, - * but the dimension is useful as metadata in some situations. - * - * @version 1.7 - */ -public class CoordinateArraySequence - implements CoordinateSequence, Serializable -{ - //With contributions from Markus Schaber [schabios@logi-track.com] 2004-03-26 - private static final long serialVersionUID = -915438501601840650L; - - /** - * The actual dimension of the coordinates in the sequence. - * Allowable values are 2 or 3. - */ - private int dimension = 3; - - private Coordinate[] coordinates; - - /** - * Constructs a sequence based on the given array - * of {@link Coordinate}s (the - * array is not copied). - * The coordinate dimension defaults to 3. - * - * @param coordinates the coordinate array that will be referenced. - */ - public CoordinateArraySequence(Coordinate[] coordinates) { - this(coordinates, 3); - } - - /** - * Constructs a sequence based on the given array - * of {@link Coordinate}s (the - * array is not copied). - * - * @param coordinates the coordinate array that will be referenced. - * @param the dimension of the coordinates - */ - public CoordinateArraySequence(Coordinate[] coordinates, int dimension) { - this.coordinates = coordinates; - this.dimension = dimension; - if (coordinates == null) - this.coordinates = new Coordinate[0]; - } - - /** - * Constructs a sequence of a given size, populated - * with new {@link Coordinate}s. - * - * @param size the size of the sequence to create - */ - public CoordinateArraySequence(int size) { - coordinates = new Coordinate[size]; - for (int i = 0; i < size; i++) { - coordinates[i] = new Coordinate(); - } - } - - /** - * Constructs a sequence of a given size, populated - * with new {@link Coordinate}s. - * - * @param size the size of the sequence to create - * @param the dimension of the coordinates - */ - public CoordinateArraySequence(int size, int dimension) { - coordinates = new Coordinate[size]; - this.dimension = dimension; - for (int i = 0; i < size; i++) { - coordinates[i] = new Coordinate(); - } - } - - /** - * Creates a new sequence based on a deep copy of the given {@link CoordinateSequence}. - * The coordinate dimension is set to equal the dimension of the input. - * - * @param coordSeq the coordinate sequence that will be copied. - */ - public CoordinateArraySequence(CoordinateSequence coordSeq) - { - // NOTE: this will make a sequence of the default dimension - if (coordSeq == null) { - coordinates = new Coordinate[0]; - return; - } - dimension = coordSeq.getDimension(); - coordinates = new Coordinate[coordSeq.size()]; - - for (int i = 0; i < coordinates.length; i++) { - coordinates[i] = coordSeq.getCoordinateCopy(i); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getDimension() - */ - public int getDimension() { return dimension; } - - /** - * Get the Coordinate with index i. - * - * @param i - * the index of the coordinate - * @return the requested Coordinate instance - */ - public Coordinate getCoordinate(int i) { - return coordinates[i]; - } - - /** - * Get a copy of the Coordinate with index i. - * - * @param i the index of the coordinate - * @return a copy of the requested Coordinate - */ - public Coordinate getCoordinateCopy(int i) { - return new Coordinate(coordinates[i]); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int) - */ - public void getCoordinate(int index, Coordinate coord) { - coord.x = coordinates[index].x; - coord.y = coordinates[index].y; - coord.z = coordinates[index].z; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int) - */ - public double getX(int index) { - return coordinates[index].x; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int) - */ - public double getY(int index) { - return coordinates[index].y; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int) - */ - public double getOrdinate(int index, int ordinateIndex) - { - switch (ordinateIndex) { - case CoordinateSequence.X: return coordinates[index].x; - case CoordinateSequence.Y: return coordinates[index].y; - case CoordinateSequence.Z: return coordinates[index].z; - } - return Double.NaN; - } - - /** - * Creates a deep copy of the Object - * - * @return The deep copy - */ - public Object clone() { - Coordinate[] cloneCoordinates = new Coordinate[size()]; - for (int i = 0; i < coordinates.length; i++) { - cloneCoordinates[i] = (Coordinate) coordinates[i].clone(); - } - return new CoordinateArraySequence(cloneCoordinates, dimension); - } - /** - * Returns the size of the coordinate sequence - * - * @return the number of coordinates - */ - public int size() { - return coordinates.length; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int, int, double) - */ - public void setOrdinate(int index, int ordinateIndex, double value) - { - switch (ordinateIndex) { - case CoordinateSequence.X: - coordinates[index].x = value; - break; - case CoordinateSequence.Y: - coordinates[index].y = value; - break; - case CoordinateSequence.Z: - coordinates[index].z = value; - break; - default: - throw new IllegalArgumentException("invalid ordinateIndex"); - } - } - - /** - * This method exposes the internal Array of Coordinate Objects - * - * @return the Coordinate[] array. - */ - public Coordinate[] toCoordinateArray() { - return coordinates; - } - - public Envelope expandEnvelope(Envelope env) - { - for (int i = 0; i < coordinates.length; i++ ) { - env.expandToInclude(coordinates[i]); - } - return env; - } - - /** - * Returns the string Representation of the coordinate array - * - * @return The string - */ - public String toString() { - if (coordinates.length > 0) { - StringBuffer strBuf = new StringBuffer(17 * coordinates.length); - strBuf.append('('); - strBuf.append(coordinates[0]); - for (int i = 1; i < coordinates.length; i++) { - strBuf.append(", "); - strBuf.append(coordinates[i]); - } - strBuf.append(')'); - return strBuf.toString(); - } else { - return "()"; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java b/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java deleted file mode 100644 index 2f553b5fe3..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java +++ /dev/null @@ -1,99 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ -package com.vividsolutions.jts.geom.impl; - -import java.io.Serializable; -import com.vividsolutions.jts.geom.*; - -/** - * Creates {@link CoordinateSequence}s represented as an array of {@link Coordinate}s. - * - * @version 1.7 - */ -public final class CoordinateArraySequenceFactory - implements CoordinateSequenceFactory, Serializable -{ - private static final long serialVersionUID = -4099577099607551657L; - private static final CoordinateArraySequenceFactory instanceObject = new CoordinateArraySequenceFactory(); - - private CoordinateArraySequenceFactory() { - } - - private Object readResolve() { - // http://www.javaworld.com/javaworld/javatips/jw-javatip122.html - return CoordinateArraySequenceFactory.instance(); - } - - /** - * Returns the singleton instance of {@link CoordinateArraySequenceFactory} - */ - public static CoordinateArraySequenceFactory instance() { - return instanceObject; - } - - /** - * Returns a {@link CoordinateArraySequence} based on the given array (the array is - * not copied). - * - * @param coordinates - * the coordinates, which may not be null nor contain null - * elements - */ - public CoordinateSequence create(Coordinate[] coordinates) { - return new CoordinateArraySequence(coordinates); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence) - */ - public CoordinateSequence create(CoordinateSequence coordSeq) { - return new CoordinateArraySequence(coordSeq); - } - - /** - * The created sequence dimension is clamped to be <= 3. - * - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int) - * - */ - public CoordinateSequence create(int size, int dimension) { - if (dimension > 3) - dimension = 3; - //throw new IllegalArgumentException("dimension must be <= 3"); - // handle bogus dimension - if (dimension < 2) - // TODO: change to dimension = 2 ??? - return new CoordinateArraySequence(size); - return new CoordinateArraySequence(size, dimension); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java b/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java deleted file mode 100644 index e2d3f0e174..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java +++ /dev/null @@ -1,493 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ -package com.vividsolutions.jts.geom.impl; - -import com.vividsolutions.jts.geom.*; - -import java.lang.ref.SoftReference; - -/** - * A {@link CoordinateSequence} implementation based on a packed arrays. - * In this implementation, {@link Coordinate}s returned by #toArray and #get are copies - * of the internal values. - * To change the actual values, use the provided setters. - *

              - * For efficiency, created Coordinate arrays - * are cached using a soft reference. - * The cache is cleared each time the coordinate sequence contents are - * modified through a setter method. - * - * @version 1.7 - */ -public abstract class PackedCoordinateSequence - implements CoordinateSequence -{ - /** - * The dimensions of the coordinates hold in the packed array - */ - protected int dimension; - - /** - * A soft reference to the Coordinate[] representation of this sequence. - * Makes repeated coordinate array accesses more efficient. - */ - protected SoftReference coordRef; - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getDimension() - */ - public int getDimension() { - return this.dimension; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int) - */ - public Coordinate getCoordinate(int i) { - Coordinate[] coords = getCachedCoords(); - if(coords != null) - return coords[i]; - else - return getCoordinateInternal(i); - } - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int) - */ - public Coordinate getCoordinateCopy(int i) { - return getCoordinateInternal(i); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int) - */ - public void getCoordinate(int i, Coordinate coord) { - coord.x = getOrdinate(i, 0); - coord.y = getOrdinate(i, 1); - if (dimension > 2) coord.z = getOrdinate(i, 2); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#toCoordinateArray() - */ - public Coordinate[] toCoordinateArray() { - Coordinate[] coords = getCachedCoords(); -// testing - never cache - if (coords != null) - return coords; - - coords = new Coordinate[size()]; - for (int i = 0; i < coords.length; i++) { - coords[i] = getCoordinateInternal(i); - } - coordRef = new SoftReference(coords); - - return coords; - } - - /** - * @return - */ - private Coordinate[] getCachedCoords() { - if (coordRef != null) { - Coordinate[] coords = (Coordinate[]) coordRef.get(); - if (coords != null) { - return coords; - } else { - // System.out.print("-"); - coordRef = null; - return null; - } - } else { - // System.out.print("-"); - return null; - } - - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int) - */ - public double getX(int index) { - return getOrdinate(index, 0); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int) - */ - public double getY(int index) { - return getOrdinate(index, 1); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int) - */ - public abstract double getOrdinate(int index, int ordinateIndex); - - /** - * Sets the first ordinate of a coordinate in this sequence. - * - * @param index the coordinate index - * @param value the new ordinate value - */ - public void setX(int index, double value) { - coordRef = null; - setOrdinate(index, 0, value); - } - - /** - * Sets the second ordinate of a coordinate in this sequence. - * - * @param index the coordinate index - * @param value the new ordinate value - */ - public void setY(int index, double value) { - coordRef = null; - setOrdinate(index, 1, value); - } - - public String toString() - { - return CoordinateSequences.toString(this); - } - - /** - * Returns a Coordinate representation of the specified coordinate, by always - * building a new Coordinate object - * - * @param index - * @return - */ - protected abstract Coordinate getCoordinateInternal(int index); - - /** - * @see java.lang.Object#clone() - */ - public abstract Object clone(); - - /** - * Sets the ordinate of a coordinate in this sequence. - *
              - * Warning: for performance reasons the ordinate index is not checked - * - if it is over dimensions you may not get an exception but a meaningless value. - * - * @param index - * the coordinate index - * @param ordinate - * the ordinate index in the coordinate, 0 based, smaller than the - * number of dimensions - * @param value - * the new ordinate value - */ - public abstract void setOrdinate(int index, int ordinate, double value); - - /** - * Packed coordinate sequence implementation based on doubles - */ - public static class Double extends PackedCoordinateSequence { - - /** - * The packed coordinate array - */ - double[] coords; - - /** - * Builds a new packed coordinate sequence - * - * @param coords - * @param dimensions - */ - public Double(double[] coords, int dimensions) { - if (dimensions < 2) { - throw new IllegalArgumentException("Must have at least 2 dimensions"); - } - if (coords.length % dimensions != 0) { - throw new IllegalArgumentException("Packed array does not contain " - + "an integral number of coordinates"); - } - this.dimension = dimensions; - this.coords = coords; - } - - /** - * Builds a new packed coordinate sequence out of a float coordinate array - * - * @param coordinates - */ - public Double(float[] coordinates, int dimensions) { - this.coords = new double[coordinates.length]; - this.dimension = dimensions; - for (int i = 0; i < coordinates.length; i++) { - this.coords[i] = coordinates[i]; - } - } - - /** - * Builds a new packed coordinate sequence out of a coordinate array - * - * @param coordinates - */ - public Double(Coordinate[] coordinates, int dimension) { - if (coordinates == null) - coordinates = new Coordinate[0]; - this.dimension = dimension; - - coords = new double[coordinates.length * this.dimension]; - for (int i = 0; i < coordinates.length; i++) { - coords[i * this.dimension] = coordinates[i].x; - if (this.dimension >= 2) - coords[i * this.dimension + 1] = coordinates[i].y; - if (this.dimension >= 3) - coords[i * this.dimension + 2] = coordinates[i].z; - } - } - /** - * Builds a new packed coordinate sequence out of a coordinate array - * - * @param coordinates - */ - public Double(Coordinate[] coordinates) { - this(coordinates, 3); - } - - /** - * Builds a new empty packed coordinate sequence of a given size and dimension - * - * @param coordinates - */ - public Double(int size, int dimension) { - this.dimension = dimension; - coords = new double[size * this.dimension]; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int) - */ - public Coordinate getCoordinateInternal(int i) { - double x = coords[i * dimension]; - double y = coords[i * dimension + 1]; - double z = dimension == 2 ? Coordinate.NULL_ORDINATE : coords[i * dimension + 2]; - return new Coordinate(x, y, z); - } - - /** - * Gets the underlying array containing the coordinate values. - * - * @return the array of coordinate values - */ - public double[] getRawCoordinates() - { - return coords; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#size() - */ - public int size() { - return coords.length / dimension; - } - - /** - * @see java.lang.Object#clone() - */ - public Object clone() { - double[] clone = new double[coords.length]; - System.arraycopy(coords, 0, clone, 0, coords.length); - return new Double(clone, dimension); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int) - * Beware, for performace reasons the ordinate index is not checked, if - * it's over dimensions you may not get an exception but a meaningless - * value. - */ - public double getOrdinate(int index, int ordinate) { - return coords[index * dimension + ordinate]; - } - - /** - * @see com.vividsolutions.jts.geom.PackedCoordinateSequence#setOrdinate(int, - * int, double) - */ - public void setOrdinate(int index, int ordinate, double value) { - coordRef = null; - coords[index * dimension + ordinate] = value; - } - - public Envelope expandEnvelope(Envelope env) - { - for (int i = 0; i < coords.length; i += dimension ) { - env.expandToInclude(coords[i], coords[i + 1]); - } - return env; - } - } - - /** - * Packed coordinate sequence implementation based on floats - */ - public static class Float extends PackedCoordinateSequence { - - /** - * The packed coordinate array - */ - float[] coords; - - /** - * Constructs a packed coordinate sequence from an array of floats - * - * @param coords - * @param dimensions - */ - public Float(float[] coords, int dimensions) { - if (dimensions < 2) { - throw new IllegalArgumentException("Must have at least 2 dimensions"); - } - if (coords.length % dimensions != 0) { - throw new IllegalArgumentException("Packed array does not contain " - + "an integral number of coordinates"); - } - this.dimension = dimensions; - this.coords = coords; - } - - /** - * Constructs a packed coordinate sequence from an array of doubles - * - * @param coordinates - * @param dimension - */ - public Float(double[] coordinates, int dimensions) { - this.coords = new float[coordinates.length]; - this.dimension = dimensions; - for (int i = 0; i < coordinates.length; i++) { - this.coords[i] = (float) coordinates[i]; - } - } - - /** - * Constructs a packed coordinate sequence out of a coordinate array - * - * @param coordinates - */ - public Float(Coordinate[] coordinates, int dimension) { - if (coordinates == null) - coordinates = new Coordinate[0]; - this.dimension = dimension; - - coords = new float[coordinates.length * this.dimension]; - for (int i = 0; i < coordinates.length; i++) { - coords[i * this.dimension] = (float) coordinates[i].x; - if (this.dimension >= 2) - coords[i * this.dimension + 1] = (float) coordinates[i].y; - if (this.dimension >= 3) - coords[i * this.dimension + 2] = (float) coordinates[i].z; - } - } - - /** - * Constructs an empty packed coordinate sequence of a given size and dimension - * - * @param coordinates - */ - public Float(int size, int dimension) { - this.dimension = dimension; - coords = new float[size * this.dimension]; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int) - */ - public Coordinate getCoordinateInternal(int i) { - double x = coords[i * dimension]; - double y = coords[i * dimension + 1]; - double z = dimension == 2 ? Coordinate.NULL_ORDINATE : coords[i * dimension + 2]; - return new Coordinate(x, y, z); - } - - /** - * Gets the underlying array containing the coordinate values. - * - * @return the array of coordinate values - */ - public float[] getRawCoordinates() - { - return coords; - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#size() - */ - public int size() { - return coords.length / dimension; - } - - /** - * @see java.lang.Object#clone() - */ - public Object clone() { - float[] clone = new float[coords.length]; - System.arraycopy(coords, 0, clone, 0, coords.length); - return new Float(clone, dimension); - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int) - * For performance reasons the ordinate index is not checked. - * If it is larger than the dimension a meaningless - * value may be returned. - */ - public double getOrdinate(int index, int ordinate) { - return coords[index * dimension + ordinate]; - } - - /** - * @see com.vividsolutions.jts.geom.PackedCoordinateSequence#setOrdinate(int, - * int, double) - */ - public void setOrdinate(int index, int ordinate, double value) { - coordRef = null; - coords[index * dimension + ordinate] = (float) value; - } - - public Envelope expandEnvelope(Envelope env) - { - for (int i = 0; i < coords.length; i += dimension ) { - env.expandToInclude(coords[i], coords[i + 1]); - } - return env; - } - - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java b/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java deleted file mode 100644 index 1c74e209f3..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java +++ /dev/null @@ -1,169 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ -package com.vividsolutions.jts.geom.impl; - -import com.vividsolutions.jts.geom.*; - -/** - * Builds packed array coordinate sequences. The array data type can be either - * double or float, and defaults to float. - */ -public class PackedCoordinateSequenceFactory implements - CoordinateSequenceFactory -{ - public static final int DOUBLE = 0; - public static final int FLOAT = 1; - - public static final PackedCoordinateSequenceFactory DOUBLE_FACTORY = - new PackedCoordinateSequenceFactory(DOUBLE); - public static final PackedCoordinateSequenceFactory FLOAT_FACTORY = - new PackedCoordinateSequenceFactory(FLOAT); - - private int type = DOUBLE; - private int dimension = 3; - - /** - * Creates a new PackedCoordinateSequenceFactory - * of type DOUBLE. - */ - public PackedCoordinateSequenceFactory() - { - this(DOUBLE); - } - - /** - * Creates a new PackedCoordinateSequenceFactory - * of the given type. - * Acceptable type values are - * {@linkplain PackedCoordinateSequenceFactory#Float}or - * {@linkplain PackedCoordinateSequenceFactory#Double} - */ - public PackedCoordinateSequenceFactory(int type) - { - this(type, 3); - } - /** - * Creates a new PackedCoordinateSequenceFactory - * of the given type. - * Acceptable type values are - * {@linkplain PackedCoordinateSequenceFactory#FLOAT}or - * {@linkplain PackedCoordinateSequenceFactory#DOUBLE} - */ - public PackedCoordinateSequenceFactory(int type, int dimension) - { - setType(type); - setDimension(dimension); - } - - /** - * Returns the type of packed coordinate sequences this factory builds, either - * {@linkplain PackedCoordinateSequenceFactory#Float} or - * {@linkplain PackedCoordinateSequenceFactory#Double} - */ - public int getType() { - return type; - } - - /** - * Sets the type of packed coordinate sequences this factory builds, - * acceptable values are {@linkplain PackedCoordinateSequenceFactory#Float}or - * {@linkplain PackedCoordinateSequenceFactory#Double} - */ - public void setType(int type) { - if (type != DOUBLE && type != FLOAT) - throw new IllegalArgumentException("Unknown type " + type); - this.type = type; - } - - - public int getDimension() { return dimension; } - - public void setDimension(int dimension) { this.dimension = dimension; } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.Coordinate[]) - */ - public CoordinateSequence create(Coordinate[] coordinates) { - if (type == DOUBLE) { - return new PackedCoordinateSequence.Double(coordinates, dimension); - } else { - return new PackedCoordinateSequence.Float(coordinates, dimension); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence) - */ - public CoordinateSequence create(CoordinateSequence coordSeq) { - if (type == DOUBLE) { - return new PackedCoordinateSequence.Double(coordSeq.toCoordinateArray(), dimension); - } else { - return new PackedCoordinateSequence.Float(coordSeq.toCoordinateArray(), dimension); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(double[], - * int) - */ - public CoordinateSequence create(double[] packedCoordinates, int dimension) { - if (type == DOUBLE) { - return new PackedCoordinateSequence.Double(packedCoordinates, dimension); - } else { - return new PackedCoordinateSequence.Float(packedCoordinates, dimension); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(float[], - * int) - */ - public CoordinateSequence create(float[] packedCoordinates, int dimension) { - if (type == DOUBLE) { - return new PackedCoordinateSequence.Double(packedCoordinates, dimension); - } else { - return new PackedCoordinateSequence.Float(packedCoordinates, dimension); - } - } - - /** - * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int) - */ - public CoordinateSequence create(int size, int dimension) { - if (type == DOUBLE) { - return new PackedCoordinateSequence.Double(size, dimension); - } else { - return new PackedCoordinateSequence.Float(size, dimension); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java b/src/main/java/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java deleted file mode 100644 index 009dbec4e8..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import java.util.*; - - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * A base class containing the logic for computes the contains - * and covers spatial relationship predicates - * for a {@link PreparedPolygon} relative to all other {@link Geometry} classes. - * Uses short-circuit tests and indexing to improve performance. - *

              - * Contains and covers are very similar, and differ only in how certain - * cases along the boundary are handled. These cases require - * full topological evaluation to handle, so all the code in - * this class is common to both predicates. - *

              - * It is not possible to short-circuit in all cases, in particular - * in the case where line segments of the test geometry touches the polygon linework. - * In this case full topology must be computed. - * (However, if the test geometry consists of only points, this - * can be evaluated in an optimized fashion. - * - * @author Martin Davis - * - */ -abstract class AbstractPreparedPolygonContains - extends PreparedPolygonPredicate -{ - /** - * This flag controls a difference between contains and covers. - * - * For contains the value is true. - * For covers the value is false. - */ - protected boolean requireSomePointInInterior = true; - - // information about geometric situation - private boolean hasSegmentIntersection = false; - private boolean hasProperIntersection = false; - private boolean hasNonProperIntersection = false; - - /** - * Creates an instance of this operation. - * - * @param prepPoly the PreparedPolygon to evaluate - */ - public AbstractPreparedPolygonContains(PreparedPolygon prepPoly) - { - super(prepPoly); - } - - /** - * Evaluate the contains or covers relationship - * for the given geometry. - * - * @param geom the test geometry - * @return true if the test geometry is contained - */ - protected boolean eval(Geometry geom) - { - /** - * Do point-in-poly tests first, since they are cheaper and may result - * in a quick negative result. - * - * If a point of any test components does not lie in target, result is false - */ - boolean isAllInTargetArea = isAllTestComponentsInTarget(geom); - if (! isAllInTargetArea) return false; - - /** - * If the test geometry consists of only Points, - * then it is now sufficient to test if any of those - * points lie in the interior of the target geometry. - * If so, the test is contained. - * If not, all points are on the boundary of the area, - * which implies not contained. - */ - if (requireSomePointInInterior - && geom.getDimension() == 0) { - boolean isAnyInTargetInterior = isAnyTestComponentInTargetInterior(geom); - return isAnyInTargetInterior; - } - - /** - * Check if there is any intersection between the line segments - * in target and test. - * In some important cases, finding a proper interesection implies that the - * test geometry is NOT contained. - * These cases are: - *

                - *
              • If the test geometry is polygonal - *
              • If the target geometry is a single polygon with no holes - *
                  - * In both of these cases, a proper intersection implies that there - * is some portion of the interior of the test geometry lying outside - * the target, which means that the test is not contained. - */ - boolean properIntersectionImpliesNotContained = isProperIntersectionImpliesNotContainedSituation(geom); - // MD - testing only -// properIntersectionImpliesNotContained = true; - - // find all intersection types which exist - findAndClassifyIntersections(geom); - - if (properIntersectionImpliesNotContained && hasProperIntersection) - return false; - - /** - * If all intersections are proper - * (i.e. no non-proper intersections occur) - * we can conclude that the test geometry is not contained in the target area, - * by the Epsilon-Neighbourhood Exterior Intersection condition. - * In real-world data this is likely to be by far the most common situation, - * since natural data is unlikely to have many exact vertex segment intersections. - * Thus this check is very worthwhile, since it avoid having to perform - * a full topological check. - * - * (If non-proper (vertex) intersections ARE found, this may indicate - * a situation where two shells touch at a single vertex, which admits - * the case where a line could cross between the shells and still be wholely contained in them. - */ - if (hasSegmentIntersection && ! hasNonProperIntersection) - return false; - - /** - * If there is a segment intersection and the situation is not one - * of the ones above, the only choice is to compute the full topological - * relationship. This is because contains/covers is very sensitive - * to the situation along the boundary of the target. - */ - if (hasSegmentIntersection) { - return fullTopologicalPredicate(geom); -// System.out.println(geom); - } - - /** - * This tests for the case where a ring of the target lies inside - * a test polygon - which implies the exterior of the Target - * intersects the interior of the Test, and hence the result is false - */ - if (geom instanceof Polygonal) { - // TODO: generalize this to handle GeometryCollections - boolean isTargetInTestArea = isAnyTargetComponentInAreaTest(geom, prepPoly.getRepresentativePoints()); - if (isTargetInTestArea) return false; - } - return true; - } - - private boolean isProperIntersectionImpliesNotContainedSituation(Geometry testGeom) - { - /** - * If the test geometry is polygonal we have the A/A situation. - * In this case, a proper intersection indicates that - * the Epsilon-Neighbourhood Exterior Intersection condition exists. - * This condition means that in some small - * area around the intersection point, there must exist a situation - * where the interior of the test intersects the exterior of the target. - * This implies the test is NOT contained in the target. - */ - if (testGeom instanceof Polygonal) return true; - /** - * A single shell with no holes allows concluding that - * a proper intersection implies not contained - * (due to the Epsilon-Neighbourhood Exterior Intersection condition) - */ - if (isSingleShell(prepPoly.getGeometry())) return true; - return false; - } - - /** - * Tests whether a geometry consists of a single polygon with no holes. - * - * @return true if the geometry is a single polygon with no holes - */ - private boolean isSingleShell(Geometry geom) - { - // handles single-element MultiPolygons, as well as Polygons - if (geom.getNumGeometries() != 1) return false; - - Polygon poly = (Polygon) geom.getGeometryN(0); - int numHoles = poly.getNumInteriorRing(); - if (numHoles == 0) return true; - return false; - } - - private void findAndClassifyIntersections(Geometry geom) - { - List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom); - - SegmentIntersectionDetector intDetector = new SegmentIntersectionDetector(); - intDetector.setFindAllIntersectionTypes(true); - prepPoly.getIntersectionFinder().intersects(lineSegStr, intDetector); - - hasSegmentIntersection = intDetector.hasIntersection(); - hasProperIntersection = intDetector.hasProperIntersection(); - hasNonProperIntersection = intDetector.hasNonProperIntersection(); - } - - /** - * Computes the full topological predicate. - * Used when short-circuit tests are not conclusive. - * - * @param geom the test geometry - * @return true if this prepared polygon has the relationship with the test geometry - */ - protected abstract boolean fullTopologicalPredicate(Geometry geom); - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java b/src/main/java/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java deleted file mode 100644 index 047e66cdc2..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.algorithm.locate.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.ComponentCoordinateExtracter; - -/** - * A base class for {@link PreparedGeometry} subclasses. - * Contains default implementations for methods, which simply delegate - * to the equivalent {@link Geometry} methods. - * This class may be used as a "no-op" class for Geometry types - * which do not have a corresponding {@link PreparedGeometry} implementation. - * - * @author Martin Davis - * - */ -class BasicPreparedGeometry - implements PreparedGeometry -{ - private final Geometry baseGeom; - private final List representativePts; // List - - public BasicPreparedGeometry(Geometry geom) - { - baseGeom = geom; - representativePts = ComponentCoordinateExtracter.getCoordinates(geom); - } - - public Geometry getGeometry() { return baseGeom; } - - /** - * Gets the list of representative points for this geometry. - * One vertex is included for every component of the geometry - * (i.e. including one for every ring of polygonal geometries). - * - * Do not modify the returned list! - * - * @return a List of Coordinate - */ - public List getRepresentativePoints() - { - //TODO wrap in unmodifiable? - return representativePts; - } - - /** - * Tests whether any representative of the target geometry - * intersects the test geometry. - * This is useful in A/A, A/L, A/P, L/P, and P/P cases. - * - * @param geom the test geometry - * @param repPts the representative points of the target geometry - * @return true if any component intersects the areal test geometry - */ - public boolean isAnyTargetComponentInTest(Geometry testGeom) - { - PointLocator locator = new PointLocator(); - for (Iterator i = representativePts.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - if (locator.intersects(p, testGeom)) - return true; - } - return false; - } - - /** - * Determines whether a Geometry g interacts with - * this geometry by testing the geometry envelopes. - * - * @param g a Geometry - * @return true if the envelopes intersect - */ - protected boolean envelopesIntersect(Geometry g) - { - if (! baseGeom.getEnvelopeInternal().intersects(g.getEnvelopeInternal())) - return false; - return true; - } - - /** - * Determines whether the envelope of - * this geometry covers the Geometry g. - * - * - * @param g a Geometry - * @return true if g is contained in this envelope - */ - protected boolean envelopeCovers(Geometry g) - { - if (! baseGeom.getEnvelopeInternal().covers(g.getEnvelopeInternal())) - return false; - return true; - } - - /** - * Default implementation. - */ - public boolean contains(Geometry g) - { - return baseGeom.contains(g); - } - - /** - * Default implementation. - */ - public boolean containsProperly(Geometry g) - { - // since raw relate is used, provide some optimizations - - // short-circuit test - if (! baseGeom.getEnvelopeInternal().contains(g.getEnvelopeInternal())) - return false; - - // otherwise, compute using relate mask - return baseGeom.relate(g, "T**FF*FF*"); - } - - /** - * Default implementation. - */ - public boolean coveredBy(Geometry g) - { - return baseGeom.coveredBy(g); - } - - /** - * Default implementation. - */ - public boolean covers(Geometry g) - { - return baseGeom.covers(g); - } - - /** - * Default implementation. - */ - public boolean crosses(Geometry g) - { - return baseGeom.crosses(g); - } - - /** - * Standard implementation for all geometries. - * Supports {@link GeometryCollection}s as input. - */ - public boolean disjoint(Geometry g) - { - return ! intersects(g); - } - - /** - * Default implementation. - */ - public boolean intersects(Geometry g) - { - return baseGeom.intersects(g); - } - - /** - * Default implementation. - */ - public boolean overlaps(Geometry g) - { - return baseGeom.overlaps(g); - } - - /** - * Default implementation. - */ - public boolean touches(Geometry g) - { - return baseGeom.touches(g); - } - - /** - * Default implementation. - */ - public boolean within(Geometry g) - { - return baseGeom.within(g); - } - - public String toString() - { - return baseGeom.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometry.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometry.java deleted file mode 100644 index e33866167e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometry.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import com.vividsolutions.jts.geom.*; - -/** - * An interface for classes which prepare {@link Geometry}s - * in order to optimize the performance - * of repeated calls to specific geometric operations. - *

                  - * A given implementation may provide optimized implementations - * for only some of the specified methods, - * and delegate the remaining methods to the original {@link Geometry} operations. - * An implementation may also only optimize certain situations, - * and delegate others. - * See the implementing classes for documentation about which methods and situations - * they optimize. - *

                  - * Subclasses are intended to be thread-safe, to allow PreparedGeometry - * to be used in a multi-threaded context - * (which allows extracting maximum benefit from the prepared state). - * - * @author Martin Davis - * - */ -public interface PreparedGeometry -{ - - /** - * Gets the original {@link Geometry} which has been prepared. - * - * @return the base geometry - */ - Geometry getGeometry(); - - /** - * Tests whether the base {@link Geometry} contains a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry contains the given Geometry - * - * @see Geometry#contains(Geometry) - */ - boolean contains(Geometry geom); - - /** - * Tests whether the base {@link Geometry} properly contains a given geometry. - *

                  - * The containsProperly predicate has the following equivalent definitions: - *

                    - *
                  • Every point of the other geometry is a point of this geometry's interior. - *
                  • The DE-9IM Intersection Matrix for the two geometries matches - * [T**FF*FF*] - *
                  - * In other words, if the test geometry has any interaction with the boundary of the target - * geometry the result of containsProperly is false. - * This is different semantics to the {@link Geometry#contains} predicate, - * in which test geometries can intersect the target's boundary and still be contained. - *

                  - * The advantage of using this predicate is that it can be computed - * efficiently, since it avoids the need to compute the full topological relationship - * of the input boundaries in cases where they intersect. - *

                  - * An example use case is computing the intersections - * of a set of geometries with a large polygonal geometry. - * Since intersection is a fairly slow operation, it can be more efficient - * to use containsProperly to filter out test geometries which lie - * wholly inside the area. In these cases the intersection is - * known a priori to be exactly the original test geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry properly contains the given Geometry - * - * @see Geometry#contains - * - */ - boolean containsProperly(Geometry geom); - - /** - * Tests whether the base {@link Geometry} is covered by a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry is covered by the given Geometry - * - * @see Geometry#coveredBy(Geometry) - */ - boolean coveredBy(Geometry geom); - - /** - * Tests whether the base {@link Geometry} covers a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry covers the given Geometry - * - * @see Geometry#covers(Geometry) - */ - boolean covers(Geometry geom); - - /** - * Tests whether the base {@link Geometry} crosses a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry crosses the given Geometry - * - * @see Geometry#crosses(Geometry) - */ - boolean crosses(Geometry geom); - - /** - * Tests whether the base {@link Geometry} is disjoint from a given geometry. - * This method supports {@link GeometryCollection}s as input - * - * @param geom the Geometry to test - * @return true if this Geometry is disjoint from the given Geometry - * - * @see Geometry#disjoint(Geometry) - */ - boolean disjoint(Geometry geom); - - /** - * Tests whether the base {@link Geometry} intersects a given geometry. - * This method supports {@link GeometryCollection}s as input - * - * @param geom the Geometry to test - * @return true if this Geometry intersects the given Geometry - * - * @see Geometry#intersects(Geometry) - */ - boolean intersects(Geometry geom); - - /** - * Tests whether the base {@link Geometry} overlaps a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry overlaps the given Geometry - * - * @see Geometry#overlaps(Geometry) - */ - boolean overlaps(Geometry geom); - - /** - * Tests whether the base {@link Geometry} touches a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry touches the given Geometry - * - * @see Geometry#touches(Geometry) - */ - boolean touches(Geometry geom); - - /** - * Tests whether the base {@link Geometry} is within a given geometry. - * - * @param geom the Geometry to test - * @return true if this Geometry is within the given Geometry - * - * @see Geometry#within(Geometry) - */ - boolean within(Geometry geom); - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometryFactory.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometryFactory.java deleted file mode 100644 index 966d26d25e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedGeometryFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import com.vividsolutions.jts.geom.*; - -/** - * A factory for creating {@link PreparedGeometry}s. - * It chooses an appropriate implementation of PreparedGeometry - * based on the geoemtric type of the input geometry. - *

                  - * In the future, the factory may accept hints that indicate - * special optimizations which can be performed. - * - * - * @author Martin Davis - * - */ -public class PreparedGeometryFactory -{ - /** - * Creates a new {@link PreparedGeometry} appropriate for the argument {@link Geometry}. - * - * @param geom the geometry to prepare - * @return the prepared geometry - */ - public static PreparedGeometry prepare(Geometry geom) - { - return (new PreparedGeometryFactory()).create(geom); - } - - public PreparedGeometryFactory() { - } - - /** - * Creates a new {@link PreparedGeometry} appropriate for the argument {@link Geometry}. - * - * @param geom the geometry to prepare - * @return the prepared geometry - */ - public PreparedGeometry create(Geometry geom) - { - if (geom instanceof Polygonal) - return new PreparedPolygon((Polygonal) geom); - if (geom instanceof Lineal) - return new PreparedLineString((Lineal) geom); - if (geom instanceof Puntal) - return new PreparedPoint((Puntal) geom); - - /** - * Default representation. - */ - return new BasicPreparedGeometry(geom); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineString.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineString.java deleted file mode 100644 index ca0d3e6f53..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineString.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.noding.*; - -/** - * A prepared version for {@link Lineal} geometries. - *

                  - * Instances of this class are thread-safe. - * - * @author mbdavis - * - */ -public class PreparedLineString - extends BasicPreparedGeometry -{ - private FastSegmentSetIntersectionFinder segIntFinder = null; - - public PreparedLineString(Lineal line) { - super((Geometry) line); - } - - public synchronized FastSegmentSetIntersectionFinder getIntersectionFinder() - { - /** - * MD - Another option would be to use a simple scan for - * segment testing for small geometries. - * However, testing indicates that there is no particular advantage - * to this approach. - */ - if (segIntFinder == null) - segIntFinder = new FastSegmentSetIntersectionFinder(SegmentStringUtil.extractSegmentStrings(getGeometry())); - return segIntFinder; - } - - public boolean intersects(Geometry g) - { - if (! envelopesIntersect(g)) return false; - return PreparedLineStringIntersects.intersects(this, g); - } - - /** - * There's not much point in trying to optimize contains, since - * contains for linear targets requires the entire test geometry - * to exactly match the target linework. - */ -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java deleted file mode 100644 index 2ef1a4b5c8..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import java.util.*; - - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Computes the intersects spatial relationship predicate - * for a target {@link PreparedLineString} relative to other {@link Geometry} classes. - * Uses short-circuit tests and indexing to improve performance. - * - * @author Martin Davis - * - */ -class PreparedLineStringIntersects -{ - /** - * Computes the intersects predicate between a {@link PreparedLineString} - * and a {@link Geometry}. - * - * @param prep the prepared linestring - * @param geom a test geometry - * @return true if the linestring intersects the geometry - */ - public static boolean intersects(PreparedLineString prep, Geometry geom) - { - PreparedLineStringIntersects op = new PreparedLineStringIntersects(prep); - return op.intersects(geom); - } - - protected PreparedLineString prepLine; - - /** - * Creates an instance of this operation. - * - * @param prepPoly the target PreparedLineString - */ - public PreparedLineStringIntersects(PreparedLineString prepLine) - { - this.prepLine = prepLine; - } - - /** - * Tests whether this geometry intersects a given geometry. - * - * @param geom the test geometry - * @return true if the test geometry intersects - */ - public boolean intersects(Geometry geom) - { - /** - * If any segments intersect, obviously intersects = true - */ - List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom); - // only request intersection finder if there are segments (ie NOT for point inputs) - if (lineSegStr.size() > 0) { - boolean segsIntersect = prepLine.getIntersectionFinder().intersects(lineSegStr); - // MD - performance testing - // boolean segsIntersect = false; - if (segsIntersect) - return true; - } - /** - * For L/L case we are done - */ - if (geom.getDimension() == 1) return false; - - /** - * For L/A case, need to check for proper inclusion of the target in the test - */ - if (geom.getDimension() == 2 - && prepLine.isAnyTargetComponentInTest(geom)) return true; - - /** - * For L/P case, need to check if any points lie on line(s) - */ - if (geom.getDimension() == 0) - return isAnyTestPointInTarget(geom); - - return false; - } - - /** - * Tests whether any representative point of the test Geometry intersects - * the target geometry. - * Only handles test geometries which are Puntal (dimension 0) - * - * @param geom a Puntal geometry to test - * @return true if any point of the argument intersects the prepared geometry - */ - protected boolean isAnyTestPointInTarget(Geometry testGeom) - { - /** - * This could be optimized by using the segment index on the lineal target. - * However, it seems like the L/P case would be pretty rare in practice. - */ - PointLocator locator = new PointLocator(); - List coords = ComponentCoordinateExtracter.getCoordinates(testGeom); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - if (locator.intersects(p, prepLine.getGeometry())) - return true; - } - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPoint.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPoint.java deleted file mode 100644 index 3390a5e325..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPoint.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import com.vividsolutions.jts.geom.*; - - -/** - * A prepared version for {@link Puntal} geometries. - *

                  - * Instances of this class are thread-safe. - * - * @author Martin Davis - * - */ -public class PreparedPoint - extends BasicPreparedGeometry -{ - public PreparedPoint(Puntal point) { - super((Geometry) point); - } - - /** - * Tests whether this point intersects a {@link Geometry}. - *

                  - * The optimization here is that computing topology for the test geometry - * is avoided. This can be significant for large geometries. - */ - public boolean intersects(Geometry g) - { - if (! envelopesIntersect(g)) return false; - - /** - * This avoids computing topology for the test geometry - */ - return isAnyTargetComponentInTest(g); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygon.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygon.java deleted file mode 100644 index 17be76f3bd..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygon.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - - -import com.vividsolutions.jts.algorithm.locate.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.operation.predicate.*; - -/** - * A prepared version for {@link Polygonal} geometries. - * This class supports both {@link Polygon}s and {@link MultiPolygon}s. - *

                  - * This class does not support MultiPolygons which are non-valid - * (e.g. with overlapping elements). - *

                  - * Instances of this class are thread-safe and immutable. - * - * @author mbdavis - * - */ -public class PreparedPolygon - extends BasicPreparedGeometry -{ - private final boolean isRectangle; - // create these lazily, since they are expensive - private FastSegmentSetIntersectionFinder segIntFinder = null; - private PointOnGeometryLocator pia = null; - - public PreparedPolygon(Polygonal poly) { - super((Geometry) poly); - isRectangle = getGeometry().isRectangle(); - } - - /** - * Gets the indexed intersection finder for this geometry. - * - * @return the intersection finder - */ - public synchronized FastSegmentSetIntersectionFinder getIntersectionFinder() - { - /** - * MD - Another option would be to use a simple scan for - * segment testing for small geometries. - * However, testing indicates that there is no particular advantage - * to this approach. - */ - if (segIntFinder == null) - segIntFinder = new FastSegmentSetIntersectionFinder(SegmentStringUtil.extractSegmentStrings(getGeometry())); - return segIntFinder; - } - - public synchronized PointOnGeometryLocator getPointLocator() - { - if (pia == null) - pia = new IndexedPointInAreaLocator(getGeometry()); - - return pia; - } - - public boolean intersects(Geometry g) - { - // envelope test - if (! envelopesIntersect(g)) return false; - - // optimization for rectangles - if (isRectangle) { - return RectangleIntersects.intersects((Polygon) getGeometry(), g); - } - - return PreparedPolygonIntersects.intersects(this, g); - } - - public boolean contains(Geometry g) - { - // short-circuit test - if (! envelopeCovers(g)) - return false; - - // optimization for rectangles - if (isRectangle) { - return RectangleContains.contains((Polygon) getGeometry(), g); - } - - return PreparedPolygonContains.contains(this, g); - } - - public boolean containsProperly(Geometry g) - { - // short-circuit test - if (! envelopeCovers(g)) - return false; - return PreparedPolygonContainsProperly.containsProperly(this, g); - } - - public boolean covers(Geometry g) - { - // short-circuit test - if (! envelopeCovers(g)) - return false; - // optimization for rectangle arguments - if (isRectangle) { - return true; - } - return PreparedPolygonCovers.covers(this, g); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java deleted file mode 100644 index 5bf35e715f..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the contains spatial relationship predicate - * for a {@link PreparedPolygon} relative to all other {@link Geometry} classes. - * Uses short-circuit tests and indexing to improve performance. - *

                  - * It is not possible to short-circuit in all cases, in particular - * in the case where the test geometry touches the polygon linework. - * In this case full topology must be computed. - * - * @author Martin Davis - * - */ -class PreparedPolygonContains - extends AbstractPreparedPolygonContains -{ - /** - * Computes the contains predicate between a {@link PreparedPolygon} - * and a {@link Geometry}. - * - * @param prep the prepared polygon - * @param geom a test geometry - * @return true if the polygon contains the geometry - */ - public static boolean contains(PreparedPolygon prep, Geometry geom) - { - PreparedPolygonContains polyInt = new PreparedPolygonContains(prep); - return polyInt.contains(geom); - } - - /** - * Creates an instance of this operation. - * - * @param prepPoly the PreparedPolygon to evaluate - */ - public PreparedPolygonContains(PreparedPolygon prepPoly) - { - super(prepPoly); - } - - /** - * Tests whether this PreparedPolygon contains a given geometry. - * - * @param geom the test geometry - * @return true if the test geometry is contained - */ - public boolean contains(Geometry geom) - { - return eval(geom); - } - - /** - * Computes the full topological contains predicate. - * Used when short-circuit tests are not conclusive. - * - * @param geom the test geometry - * @return true if this prepared polygon contains the test geometry - */ - protected boolean fullTopologicalPredicate(Geometry geom) - { - boolean isContained = prepPoly.getGeometry().contains(geom); - return isContained; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java deleted file mode 100644 index bd92d3795c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import java.util.*; - - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Computes the containsProperly spatial relationship predicate - * for {@link PreparedPolygon}s relative to all other {@link Geometry} classes. - * Uses short-circuit tests and indexing to improve performance. - *

                  - * A Geometry A containsProperly another Geometry B iff - * all points of B are contained in the Interior of A. - * Equivalently, B is contained in A AND B does not intersect - * the Boundary of A. - *

                  - * The advantage to using this predicate is that it can be computed - * efficiently, with no need to compute topology at individual points. - * In a situation with many geometries intersecting the boundary - * of the target geometry, this can make a performance difference. - * - * @author Martin Davis - */ -class PreparedPolygonContainsProperly - extends PreparedPolygonPredicate -{ - /** - * Computes the containsProperly predicate between a {@link PreparedPolygon} - * and a {@link Geometry}. - * - * @param prep the prepared polygon - * @param geom a test geometry - * @return true if the polygon properly contains the geometry - */ - public static boolean containsProperly(PreparedPolygon prep, Geometry geom) - { - PreparedPolygonContainsProperly polyInt = new PreparedPolygonContainsProperly(prep); - return polyInt.containsProperly(geom); - } - - /** - * Creates an instance of this operation. - * - * @param prepPoly the PreparedPolygon to evaluate - */ - public PreparedPolygonContainsProperly(PreparedPolygon prepPoly) - { - super(prepPoly); - } - - /** - * Tests whether this PreparedPolygon containsProperly a given geometry. - * - * @param geom the test geometry - * @return true if the test geometry is contained properly - */ - public boolean containsProperly(Geometry geom) - { - /** - * Do point-in-poly tests first, since they are cheaper and may result - * in a quick negative result. - * - * If a point of any test components does not lie in the target interior, result is false - */ - boolean isAllInPrepGeomAreaInterior = isAllTestComponentsInTargetInterior(geom); - if (! isAllInPrepGeomAreaInterior) return false; - - /** - * If any segments intersect, result is false. - */ - List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom); - boolean segsIntersect = prepPoly.getIntersectionFinder().intersects(lineSegStr); - if (segsIntersect) - return false; - - /** - * Given that no segments intersect, if any vertex of the target - * is contained in some test component. - * the test is NOT properly contained. - */ - if (geom instanceof Polygonal) { - // TODO: generalize this to handle GeometryCollections - boolean isTargetGeomInTestArea = isAnyTargetComponentInAreaTest(geom, prepPoly.getRepresentativePoints()); - if (isTargetGeomInTestArea) return false; - } - - return true; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java deleted file mode 100644 index 1ca993b254..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the covers spatial relationship predicate - * for a {@link PreparedPolygon} relative to all other {@link Geometry} classes. - * Uses short-circuit tests and indexing to improve performance. - *

                  - * It is not possible to short-circuit in all cases, in particular - * in the case where the test geometry touches the polygon linework. - * In this case full topology must be computed. - * - * @author Martin Davis - * - */ -class PreparedPolygonCovers - extends AbstractPreparedPolygonContains -{ - /** - * Computes the covers predicate between a {@link PreparedPolygon} - * and a {@link Geometry}. - * - * @param prep the prepared polygon - * @param geom a test geometry - * @return true if the polygon covers the geometry - */ - public static boolean covers(PreparedPolygon prep, Geometry geom) - { - PreparedPolygonCovers polyInt = new PreparedPolygonCovers(prep); - return polyInt.covers(geom); - } - - /** - * Creates an instance of this operation. - * - * @param prepPoly the PreparedPolygon to evaluate - */ - public PreparedPolygonCovers(PreparedPolygon prepPoly) - { - super(prepPoly); - requireSomePointInInterior = false; - } - - /** - * Tests whether this PreparedPolygon covers a given geometry. - * - * @param geom the test geometry - * @return true if the test geometry is covered - */ - public boolean covers(Geometry geom) - { - return eval(geom); - } - - /** - * Computes the full topological covers predicate. - * Used when short-circuit tests are not conclusive. - * - * @param geom the test geometry - * @return true if this prepared polygon covers the test geometry - */ - protected boolean fullTopologicalPredicate(Geometry geom) - { - boolean result = prepPoly.getGeometry().covers(geom); - return result; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java deleted file mode 100644 index 41f71a1cae..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.prep; - -import java.util.List; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.noding.SegmentStringUtil; - -/** - * Computes the intersects spatial relationship predicate for - * {@link PreparedPolygon}s relative to all other {@link Geometry} classes. Uses - * short-circuit tests and indexing to improve performance. - * - * @author Martin Davis - * - */ -class PreparedPolygonIntersects extends PreparedPolygonPredicate { - /** - * Computes the intersects predicate between a {@link PreparedPolygon} and a - * {@link Geometry}. - * - * @param prep - * the prepared polygon - * @param geom - * a test geometry - * @return true if the polygon intersects the geometry - */ - public static boolean intersects(PreparedPolygon prep, Geometry geom) { - PreparedPolygonIntersects polyInt = new PreparedPolygonIntersects(prep); - return polyInt.intersects(geom); - } - - /** - * Creates an instance of this operation. - * - * @param prepPoly - * the PreparedPolygon to evaluate - */ - public PreparedPolygonIntersects(PreparedPolygon prepPoly) { - super(prepPoly); - } - - /** - * Tests whether this PreparedPolygon intersects a given geometry. - * - * @param geom - * the test geometry - * @return true if the test geometry intersects - */ - public boolean intersects(Geometry geom) { - /** - * Do point-in-poly tests first, since they are cheaper and may result in a - * quick positive result. - * - * If a point of any test components lie in target, result is true - */ - boolean isInPrepGeomArea = isAnyTestComponentInTarget(geom); - if (isInPrepGeomArea) - return true; - /** - * If input contains only points, then at - * this point it is known that none of them are contained in the target - */ - if (geom.getDimension() == 0) - return false; - /** - * If any segments intersect, result is true - */ - List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom); - // only request intersection finder if there are segments - // (i.e. NOT for point inputs) - if (lineSegStr.size() > 0) { - boolean segsIntersect = prepPoly.getIntersectionFinder().intersects( - lineSegStr); - if (segsIntersect) - return true; - } - - /** - * If the test has dimension = 2 as well, it is necessary to test for proper - * inclusion of the target. Since no segments intersect, it is sufficient to - * test representative points. - */ - if (geom.getDimension() == 2) { - // TODO: generalize this to handle GeometryCollections - boolean isPrepGeomInArea = isAnyTargetComponentInAreaTest(geom, - prepPoly.getRepresentativePoints()); - if (isPrepGeomInArea) - return true; - } - - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java b/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java deleted file mode 100644 index f8ff3109c9..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java +++ /dev/null @@ -1,167 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.prep; - -import java.util.*; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.algorithm.locate.PointOnGeometryLocator; -import com.vividsolutions.jts.algorithm.locate.SimplePointInAreaLocator; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * A base class for predicate operations on {@link PreparedPolygon}s. - * - * @author mbdavis - * - */ -abstract class PreparedPolygonPredicate -{ - protected PreparedPolygon prepPoly; - private PointOnGeometryLocator targetPointLocator; - - /** - * Creates an instance of this operation. - * - * @param prepPoly the PreparedPolygon to evaluate - */ - public PreparedPolygonPredicate(PreparedPolygon prepPoly) - { - this.prepPoly = prepPoly; - targetPointLocator = prepPoly.getPointLocator(); - } - - /** - * Tests whether all components of the test Geometry - * are contained in the target geometry. - * Handles both linear and point components. - * - * @param geom a geometry to test - * @return true if all componenta of the argument are contained in the target geometry - */ - protected boolean isAllTestComponentsInTarget(Geometry testGeom) - { - List coords = ComponentCoordinateExtracter.getCoordinates(testGeom); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - int loc = targetPointLocator.locate(p); - if (loc == Location.EXTERIOR) - return false; - } - return true; - } - - /** - * Tests whether all components of the test Geometry - * are contained in the interior of the target geometry. - * Handles both linear and point components. - * - * @param geom a geometry to test - * @return true if all componenta of the argument are contained in the target geometry interior - */ - protected boolean isAllTestComponentsInTargetInterior(Geometry testGeom) - { - List coords = ComponentCoordinateExtracter.getCoordinates(testGeom); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - int loc = targetPointLocator.locate(p); - if (loc != Location.INTERIOR) - return false; - } - return true; - } - - /** - * Tests whether any component of the test Geometry intersects - * the area of the target geometry. - * Handles test geometries with both linear and point components. - * - * @param geom a geometry to test - * @return true if any component of the argument intersects the prepared area geometry - */ - protected boolean isAnyTestComponentInTarget(Geometry testGeom) - { - List coords = ComponentCoordinateExtracter.getCoordinates(testGeom); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - int loc = targetPointLocator.locate(p); - if (loc != Location.EXTERIOR) - return true; - } - return false; - } - - /** - * Tests whether any component of the test Geometry intersects - * the interior of the target geometry. - * Handles test geometries with both linear and point components. - * - * @param geom a geometry to test - * @return true if any component of the argument intersects the prepared area geometry interior - */ - protected boolean isAnyTestComponentInTargetInterior(Geometry testGeom) - { - List coords = ComponentCoordinateExtracter.getCoordinates(testGeom); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - int loc = targetPointLocator.locate(p); - if (loc == Location.INTERIOR) - return true; - } - return false; - } - - - /** - * Tests whether any component of the target geometry - * intersects the test geometry (which must be an areal geometry) - * - * @param geom the test geometry - * @param repPts the representative points of the target geometry - * @return true if any component intersects the areal test geometry - */ - protected boolean isAnyTargetComponentInAreaTest(Geometry testGeom, List targetRepPts) - { - PointOnGeometryLocator piaLoc = new SimplePointInAreaLocator(testGeom); - for (Iterator i = targetRepPts.iterator(); i.hasNext(); ) { - Coordinate p = (Coordinate) i.next(); - int loc = piaLoc.locate(p); - if (loc != Location.EXTERIOR) - return true; - } - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformation.java b/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformation.java deleted file mode 100644 index d76650b030..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformation.java +++ /dev/null @@ -1,1115 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -/** - * Represents an affine transformation on the 2D Cartesian plane. - * It can be used to transform a {@link Coordinate} or {@link Geometry}. - * An affine transformation is a mapping of the 2D plane into itself - * via a series of transformations of the following basic types: - *

                    - *
                  • reflection (through a line) - *
                  • rotation (around the origin) - *
                  • scaling (relative to the origin) - *
                  • shearing (in both the X and Y directions) - *
                  • translation - *
                  - * In general, affine transformations preserve straightness and parallel lines, - * but do not preserve distance or shape. - *

                  - * An affine transformation can be represented by a 3x3 - * matrix in the following form: - *

                  - * T = | m00 m01 m02 |
                  - *     | m10 m11 m12 |
                  - *     |  0   0   1  |
                  - * 
                  - * A coordinate P = (x, y) can be transformed to a new coordinate P' = (x', y') - * by representing it as a 3x1 matrix and using matrix multiplication to compute: - *
                  - * | x' |  = T x | x |
                  - * | y' |        | y |
                  - * | 1  |        | 1 |
                  - * 
                  - *

                  Transformation Composition

                  - * Affine transformations can be composed using the {@link #compose} method. - * Composition is computed via multiplication of the - * transformation matrices, and is defined as: - *
                  - * A.compose(B) = TB x TA
                  - * 
                  - * This produces a transformation whose effect is that of A followed by B. - * The methods {@link #reflect}, {@link #rotate}, - * {@link #scale}, {@link #shear}, and {@link #translate} - * have the effect of composing a transformation of that type with - * the transformation they are invoked on. - *

                  - * The composition of transformations is in general not commutative. - * - *

                  Transformation Inversion

                  - * Affine transformations may be invertible or non-invertible. - * If a transformation is invertible, then there exists - * an inverse transformation which when composed produces - * the identity transformation. - * The {@link #getInverse} method - * computes the inverse of a transformation, if one exists. - * - * @author Martin Davis - * - */ -public class AffineTransformation - implements Cloneable, CoordinateSequenceFilter -{ - - /** - * Creates a transformation for a reflection about the - * line (x0,y0) - (x1,y1). - * - * @param x0 the x-ordinate of a point on the reflection line - * @param y0 the y-ordinate of a point on the reflection line - * @param x1 the x-ordinate of a another point on the reflection line - * @param y1 the y-ordinate of a another point on the reflection line - * @return a transformation for the reflection - */ - public static AffineTransformation reflectionInstance(double x0, double y0, double x1, double y1) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToReflection(x0, y0, x1, y1); - return trans; - } - - /** - * Creates a transformation for a reflection about the - * line (0,0) - (x,y). - * - * @param x the x-ordinate of a point on the reflection line - * @param y the y-ordinate of a point on the reflection line - * @return a transformation for the reflection - */ - public static AffineTransformation reflectionInstance(double x, double y) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToReflection(x, y); - return trans; - } - - /** - * Creates a transformation for a rotation - * about the origin - * by an angle theta. - * Positive angles correspond to a rotation - * in the counter-clockwise direction. - * - * @param theta the rotation angle, in radians - * @return a transformation for the rotation - */ - public static AffineTransformation rotationInstance(double theta) - { - return rotationInstance(Math.sin(theta), Math.cos(theta)); - } - - /** - * Creates a transformation for a rotation - * by an angle theta, - * specified by the sine and cosine of the angle. - * This allows providing exact values for sin(theta) and cos(theta) - * for the common case of rotations of multiples of quarter-circles. - * - * @param sinTheta the sine of the rotation angle - * @param cosTheta the cosine of the rotation angle - * @return a transformation for the rotation - */ - public static AffineTransformation rotationInstance(double sinTheta, double cosTheta) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToRotation(sinTheta, cosTheta); - return trans; - } - - /** - * Creates a transformation for a rotation - * about the point (x,y) by an angle theta. - * Positive angles correspond to a rotation - * in the counter-clockwise direction. - * - * @param theta the rotation angle, in radians - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return a transformation for the rotation - */ - public static AffineTransformation rotationInstance(double theta, double x, double y) - { - return rotationInstance(Math.sin(theta), Math.cos(theta), x, y); - } - - /** - * Creates a transformation for a rotation - * about the point (x,y) by an angle theta, - * specified by the sine and cosine of the angle. - * This allows providing exact values for sin(theta) and cos(theta) - * for the common case of rotations of multiples of quarter-circles. - * - * @param sinTheta the sine of the rotation angle - * @param cosTheta the cosine of the rotation angle - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return a transformation for the rotation - */ - public static AffineTransformation rotationInstance(double sinTheta, double cosTheta, double x, double y) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToRotation(sinTheta, cosTheta, x, y); - return trans; - } - - /** - * Creates a transformation for a scaling relative to the origin. - * - * @param xScale the value to scale by in the x direction - * @param yScale the value to scale by in the y direction - * @return a transformation for the scaling - */ - public static AffineTransformation scaleInstance(double xScale, double yScale) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToScale(xScale, yScale); - return trans; - } - - /** - * Creates a transformation for a scaling relative to the point (x,y). - * - * @param xScale the value to scale by in the x direction - * @param yScale the value to scale by in the y direction - * @param x the x-ordinate of the point to scale around - * @param y the y-ordinate of the point to scale around - * @return a transformation for the scaling - */ - public static AffineTransformation scaleInstance(double xScale, double yScale, double x, double y) - { - AffineTransformation trans = new AffineTransformation(); - trans.translate(-x, -y); - trans.scale(xScale, yScale); - trans.translate(x, y); - return trans; - } - - - /** - * Creates a transformation for a shear. - * - * @param xShear the value to shear by in the x direction - * @param yShear the value to shear by in the y direction - * @return a tranformation for the shear - */ - public static AffineTransformation shearInstance(double xShear, double yShear) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToShear(xShear, yShear); - return trans; - } - - /** - * Creates a transformation for a translation. - * - * @param x the value to translate by in the x direction - * @param y the value to translate by in the y direction - * @return a tranformation for the translation - */ - public static AffineTransformation translationInstance(double x, double y) - { - AffineTransformation trans = new AffineTransformation(); - trans.setToTranslation(x, y); - return trans; - } - - // affine matrix entries - // (bottom row is always [ 0 0 1 ]) - private double m00; - private double m01; - private double m02; - private double m10; - private double m11; - private double m12; - - /** - * Constructs a new identity transformation - */ - public AffineTransformation() - { - setToIdentity(); - } - - /** - * Constructs a new transformation whose - * matrix has the specified values. - * - * @param matrix an array containing the 6 values { m00, m01, m02, m10, m11, m12 } - * @throws NullPointerException if matrix is null - * @throws ArrayIndexOutOfBoundsException if matrix is too small - */ - public AffineTransformation(double[] matrix) - { - m00 = matrix[0]; - m01 = matrix[1]; - m02 = matrix[2]; - m10 = matrix[3]; - m11 = matrix[4]; - m12 = matrix[5]; - } - - /** - * Constructs a new transformation whose - * matrix has the specified values. - * - * @param m00 the entry for the [0, 0] element in the transformation matrix - * @param m01 the entry for the [0, 1] element in the transformation matrix - * @param m02 the entry for the [0, 2] element in the transformation matrix - * @param m10 the entry for the [1, 0] element in the transformation matrix - * @param m11 the entry for the [1, 1] element in the transformation matrix - * @param m12 the entry for the [1, 2] element in the transformation matrix - */ - public AffineTransformation(double m00, - double m01, - double m02, - double m10, - double m11, - double m12) - { - setTransformation(m00, m01, m02, m10, m11, m12); - } - - /** - * Constructs a transformation which is - * a copy of the given one. - * - * @param trans the transformation to copy - */ - public AffineTransformation(AffineTransformation trans) - { - setTransformation(trans); - } - - /** - * Constructs a transformation - * which maps the given source - * points into the given destination points. - * - * @param src0 source point 0 - * @param src1 source point 1 - * @param src2 source point 2 - * @param dest0 the mapped point for source point 0 - * @param dest1 the mapped point for source point 1 - * @param dest2 the mapped point for source point 2 - * - */ - public AffineTransformation(Coordinate src0, - Coordinate src1, - Coordinate src2, - Coordinate dest0, - Coordinate dest1, - Coordinate dest2) - { - } - - /** - * Sets this transformation to be the identity transformation. - * The identity transformation has the matrix: - *
                  -   * | 1 0 0 |
                  -   * | 0 1 0 |
                  -   * | 0 0 1 |
                  -   * 
                  - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToIdentity() - { - m00 = 1.0; m01 = 0.0; m02 = 0.0; - m10 = 0.0; m11 = 1.0; m12 = 0.0; - return this; - } - - /** - * Sets this transformation's matrix to have the given values. - * - * @param m00 the entry for the [0, 0] element in the transformation matrix - * @param m01 the entry for the [0, 1] element in the transformation matrix - * @param m02 the entry for the [0, 2] element in the transformation matrix - * @param m10 the entry for the [1, 0] element in the transformation matrix - * @param m11 the entry for the [1, 1] element in the transformation matrix - * @param m12 the entry for the [1, 2] element in the transformation matrix - * @return this transformation, with an updated matrix - */ - public AffineTransformation setTransformation(double m00, - double m01, - double m02, - double m10, - double m11, - double m12) - { - this.m00 = m00; - this.m01 = m01; - this.m02 = m02; - this.m10 = m10; - this.m11 = m11; - this.m12 = m12; - return this; - } - - /** - * Sets this transformation to be a copy of the given one - * - * @param trans a transformation to copy - * @return this transformation, with an updated matrix - */ - public AffineTransformation setTransformation(AffineTransformation trans) - { - m00 = trans.m00; m01 = trans.m01; m02 = trans.m02; - m10 = trans.m10; m11 = trans.m11; m12 = trans.m12; - return this; - } - - /** - * Gets an array containing the entries - * of the transformation matrix. - * Only the 6 non-trivial entries are returned, - * in the sequence: - *
                  -   * m00, m01, m02, m10, m11, m12
                  -   * 
                  - * - * @return an array of length 6 - */ - public double[] getMatrixEntries() - { - return new double[] { m00, m01, m02, m10, m11, m12 }; - } - - /** - * Computes the determinant of the transformation matrix. - * The determinant is computed as: - *
                  -  * | m00 m01 m02 |
                  -  * | m10 m11 m12 | = m00 * m11 - m01 * m10
                  -  * |  0   0   1  |
                  -  * 
                  - * If the determinant is zero, - * the transform is singular (not invertible), - * and operations which attempt to compute - * an inverse will throw a NoninvertibleTransformException. - - * @return the determinant of the transformation - * @see #getInverse() - */ - public double getDeterminant() - { - return m00 * m11 - m01 * m10; - } - - /** - * Computes the inverse of this transformation, if one - * exists. - * The inverse is the transformation which when - * composed with this one produces the identity - * transformation. - * A transformation has an inverse if and only if it - * is not singular (i.e. its - * determinant is non-zero). - * Geometrically, an transformation is non-invertible - * if it maps the plane to a line or a point. - * If no inverse exists this method - * will throw a NoninvertibleTransformationException. - *

                  - * The matrix of the inverse is equal to the - * inverse of the matrix for the transformation. - * It is computed as follows: - *

                    
                  -   *                 1    
                  -   * inverse(A)  =  ---   x  adjoint(A) 
                  -   *                det 
                  -   *
                  -   *
                  -   *             =   1       |  m11  -m01   m01*m12-m02*m11  |
                  -   *                ---   x  | -m10   m00  -m00*m12+m10*m02  |
                  -   *                det      |  0     0     m00*m11-m10*m01  |
                  -   *
                  -   *
                  -   *
                  -   *             = |  m11/det  -m01/det   m01*m12-m02*m11/det |
                  -   *               | -m10/det   m00/det  -m00*m12+m10*m02/det |
                  -   *               |   0           0          1               |
                  -   *
                  -   * 
                  - * - * @return a new inverse transformation - * @throws NoninvertibleTransformationException - * @see #getDeterminant() - */ - public AffineTransformation getInverse() - throws NoninvertibleTransformationException - { - double det = getDeterminant(); - if (det == 0) - throw new NoninvertibleTransformationException("Transformation is non-invertible"); - - double im00 = m11 / det; - double im10 = -m10 / det; - double im01 = -m01 / det; - double im11 = m00 / det; - double im02 = (m01 * m12 - m02 * m11) / det; - double im12 = (-m00 * m12 + m10 * m02) / det; - - return new AffineTransformation(im00, im01, im02, im10, im11, im12); - } - - /** - * Explicitly computes the math for a reflection. May not work. - * @param x0 the X ordinate of one point on the reflection line - * @param y0 the Y ordinate of one point on the reflection line - * @param x1 the X ordinate of another point on the reflection line - * @param y1 the Y ordinate of another point on the reflection line - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToReflectionBasic(double x0, double y0, double x1, double y1) - { - if (x0 == x1 && y0 == y1) { - throw new IllegalArgumentException("Reflection line points must be distinct"); - } - double dx = x1 - x0; - double dy = y1 - y0; - double d = Math.sqrt(dx * dx + dy * dy); - double sin = dy / d; - double cos = dx / d; - double cs2 = 2 * sin * cos; - double c2s2 = cos * cos - sin * sin; - m00 = c2s2; m01 = cs2; m02 = 0.0; - m10 = cs2; m11 = -c2s2; m12 = 0.0; - return this; - } - - /** - * Sets this transformation to be a reflection - * about the line defined by a line (x0,y0) - (x1,y1). - * - * @param x0 the X ordinate of one point on the reflection line - * @param y0 the Y ordinate of one point on the reflection line - * @param x1 the X ordinate of another point on the reflection line - * @param y1 the Y ordinate of another point on the reflection line - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToReflection(double x0, double y0, double x1, double y1) - { - if (x0 == x1 && y0 == y1) { - throw new IllegalArgumentException("Reflection line points must be distinct"); - } - // translate line vector to origin - setToTranslation(-x0, -y0); - - // rotate vector to positive x axis direction - double dx = x1 - x0; - double dy = y1 - y0; - double d = Math.sqrt(dx * dx + dy * dy); - double sin = dy / d; - double cos = dx / d; - rotate(-sin, cos); - // reflect about the x axis - scale(1, -1); - // rotate back - rotate(sin, cos); - // translate back - translate(x0, y0); - return this; - } - - /** - * Sets this transformation to be a reflection - * about the line defined by vector (x,y). - * The transformation for a reflection - * is computed by: - *
                  -   * d = sqrt(x2 + y2)  
                  -   * sin = y / d;
                  -   * cos = x / d;
                  -   * 
                  -   * Tref = Trot(sin, cos) x Tscale(1, -1) x Trot(-sin, cos)
                  - * - * @param x the x-component of the reflection line vector - * @param y the y-component of the reflection line vector - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToReflection(double x, double y) - { - if (x == 0.0 && y == 0.0) { - throw new IllegalArgumentException("Reflection vector must be non-zero"); - } - - /** - * Handle special case - x = y. - * This case is specified explicitly to avoid roundoff error. - */ - if (x == y) { - m00 = 0.0; - m01 = 1.0; - m02 = 0.0; - m10 = 1.0; - m11 = 0.0; - m12 = 0.0; - return this; - } - - // rotate vector to positive x axis direction - double d = Math.sqrt(x * x + y * y); - double sin = y / d; - double cos = x / d; - rotate(-sin, cos); - // reflect about the x-axis - scale(1, -1); - // rotate back - rotate(sin, cos); - return this; - } - - /** - * Sets this transformation to be a rotation around the origin. - * A positive rotation angle corresponds - * to a counter-clockwise rotation. - * The transformation matrix for a rotation - * by an angle theta - * has the value: - *
                    
                  -   * |  cos(theta)  -sin(theta)   0 |
                  -   * |  sin(theta)   cos(theta)   0 |
                  -   * |           0            0   1 |
                  -   * 
                  - * - * @param theta the rotation angle, in radians - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToRotation(double theta) - { - setToRotation(Math.sin(theta), Math.cos(theta)); - return this; - } - - /** - * Sets this transformation to be a rotation around the origin - * by specifying the sin and cos of the rotation angle directly. - * The transformation matrix for the rotation - * has the value: - *
                    
                  -   * |  cosTheta  -sinTheta   0 |
                  -   * |  sinTheta   cosTheta   0 |
                  -   * |         0          0   1 |
                  -   * 
                  - * - * @param sinTheta the sine of the rotation angle - * @param cosTheta the cosine of the rotation angle - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToRotation(double sinTheta, double cosTheta) - { - m00 = cosTheta; m01 = -sinTheta; m02 = 0.0; - m10 = sinTheta; m11 = cosTheta; m12 = 0.0; - return this; - } - - /** - * Sets this transformation to be a rotation - * around a given point (x,y). - * A positive rotation angle corresponds - * to a counter-clockwise rotation. - * The transformation matrix for a rotation - * by an angle theta - * has the value: - *
                    
                  -   * |  cosTheta  -sinTheta   x-x*cos+y*sin |
                  -   * |  sinTheta   cosTheta   y-x*sin-y*cos |
                  -   * |           0            0   1 |
                  -   * 
                  - * - * @param theta the rotation angle, in radians - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToRotation(double theta, double x, double y) - { - setToRotation(Math.sin(theta), Math.cos(theta), x, y); - return this; - } - - - /** - * Sets this transformation to be a rotation - * around a given point (x,y) - * by specifying the sin and cos of the rotation angle directly. - * The transformation matrix for the rotation - * has the value: - *
                    
                  -   * |  cosTheta  -sinTheta   x-x*cos+y*sin |
                  -   * |  sinTheta   cosTheta   y-x*sin-y*cos |
                  -   * |         0          0         1       |
                  -   * 
                  - * - * @param sinTheta the sine of the rotation angle - * @param cosTheta the cosine of the rotation angle - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToRotation(double sinTheta, double cosTheta, double x, double y) - { - m00 = cosTheta; m01 = -sinTheta; m02 = x - x * cosTheta + y * sinTheta; - m10 = sinTheta; m11 = cosTheta; m12 = y - x * sinTheta - y * cosTheta; - return this; - } - - /** - * Sets this transformation to be a scaling. - * The transformation matrix for a scale - * has the value: - *
                    
                  -   * |  xScale      0  dx |
                  -   * |  1      yScale  dy |
                  -   * |  0           0   1 |
                  -   * 
                  - * - * @param xScale the amount to scale x-ordinates by - * @param yScale the amount to scale y-ordinates by - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToScale(double xScale, double yScale) - { - m00 = xScale; m01 = 0.0; m02 = 0.0; - m10 = 0.0; m11 = yScale; m12 = 0.0; - return this; - } - - /** - * Sets this transformation to be a shear. - * The transformation matrix for a shear - * has the value: - *
                    
                  -   * |  1      xShear  0 |
                  -   * |  yShear      1  0 |
                  -   * |  0           0  1 |
                  -   * 
                  - * Note that a shear of (1, 1) is not - * equal to shear(1, 0) composed with shear(0, 1). - * Instead, shear(1, 1) corresponds to a mapping onto the - * line x = y. - * - * @param xShear the x component to shear by - * @param yShear the y component to shear by - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToShear(double xShear, double yShear) - { - m00 = 1.0; m01 = xShear; m02 = 0.0; - m10 = yShear; m11 = 1.0; m12 = 0.0; - return this; - } - - /** - * Sets this transformation to be a translation. - * For a translation by the vector (x, y) - * the transformation matrix has the value: - *
                    
                  -   * |  1  0  dx |
                  -   * |  1  0  dy |
                  -   * |  0  0   1 |
                  -   * 
                  - * @param dx the x component to translate by - * @param dy the y component to translate by - * @return this transformation, with an updated matrix - */ - public AffineTransformation setToTranslation(double dx, double dy) - { - m00 = 1.0; m01 = 0.0; m02 = dx; - m10 = 0.0; m11 = 1.0; m12 = dy; - return this; - } - - /** - * Updates the value of this transformation - * to that of a reflection transformation composed - * with the current value. - * - * @param x0 the x-ordinate of a point on the line to reflect around - * @param y0 the y-ordinate of a point on the line to reflect around - * @param x1 the x-ordinate of a point on the line to reflect around - * @param y1 the y-ordinate of a point on the line to reflect around - * @return this transformation, with an updated matrix - */ - public AffineTransformation reflect(double x0, double y0, double x1, double y1) - { - compose(reflectionInstance(x0, y0, x1, y1)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a reflection transformation composed - * with the current value. - * - * @param x the x-ordinate of the line to reflect around - * @param y the y-ordinate of the line to reflect around - * @return this transformation, with an updated matrix - */ - public AffineTransformation reflect(double x, double y) - { - compose(reflectionInstance(x, y)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a rotation transformation composed - * with the current value. - * Positive angles correspond to a rotation - * in the counter-clockwise direction. - * - * @param theta the angle to rotate by, in radians - * @return this transformation, with an updated matrix - */ - public AffineTransformation rotate(double theta) - { - compose(rotationInstance(theta)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a rotation around the origin composed - * with the current value, - * with the sin and cos of the rotation angle specified directly. - * - * @param sinTheta the sine of the angle to rotate by - * @param cosTheta the cosine of the angle to rotate by - * @return this transformation, with an updated matrix - */ - public AffineTransformation rotate(double sinTheta, double cosTheta) - { - compose(rotationInstance(sinTheta, cosTheta)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a rotation around a given point composed - * with the current value. - * Positive angles correspond to a rotation - * in the counter-clockwise direction. - * - * @param theta the angle to rotate by, in radians - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return this transformation, with an updated matrix - */ - public AffineTransformation rotate(double theta, double x, double y) - { - compose(rotationInstance(theta, x, y)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a rotation around a given point composed - * with the current value, - * with the sin and cos of the rotation angle specified directly. - * - * @param sinTheta the sine of the angle to rotate by - * @param cosTheta the cosine of the angle to rotate by - * @param x the x-ordinate of the rotation point - * @param y the y-ordinate of the rotation point - * @return this transformation, with an updated matrix - */ - public AffineTransformation rotate(double sinTheta, double cosTheta, double x, double y) - { - compose(rotationInstance(sinTheta, cosTheta)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a scale transformation composed - * with the current value. - * - * @param xScale the value to scale by in the x direction - * @param yScale the value to scale by in the y direction - * @return this transformation, with an updated matrix - */ - public AffineTransformation scale(double xScale, double yScale) - { - compose(scaleInstance(xScale, yScale)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a shear transformation composed - * with the current value. - * - * @param xShear the value to shear by in the x direction - * @param yShear the value to shear by in the y direction - * @return this transformation, with an updated matrix - */ - public AffineTransformation shear(double xShear, double yShear) - { - compose(shearInstance(xShear, yShear)); - return this; - } - - /** - * Updates the value of this transformation - * to that of a translation transformation composed - * with the current value. - * - * @param x the value to translate by in the x direction - * @param y the value to translate by in the y direction - * @return this transformation, with an updated matrix - */ - public AffineTransformation translate(double x, double y) - { - compose(translationInstance(x, y)); - return this; - } - - - /** - * Updates this transformation to be - * the composition of this transformation with the given {@link AffineTransformation}. - * This produces a transformation whose effect - * is equal to applying this transformation - * followed by the argument transformation. - * Mathematically, - *
                  -   * A.compose(B) = TB x TA
                  -   * 
                  - * - * @param trans an affine transformation - * @return this transformation, with an updated matrix - */ - public AffineTransformation compose(AffineTransformation trans) - { - double mp00 = trans.m00 * m00 + trans.m01 * m10; - double mp01 = trans.m00 * m01 + trans.m01 * m11; - double mp02 = trans.m00 * m02 + trans.m01 * m12 + trans.m02; - double mp10 = trans.m10 * m00 + trans.m11 * m10; - double mp11 = trans.m10 * m01 + trans.m11 * m11; - double mp12 = trans.m10 * m02 + trans.m11 * m12 + trans.m12; - m00 = mp00; - m01 = mp01; - m02 = mp02; - m10 = mp10; - m11 = mp11; - m12 = mp12; - return this; - } - - /** - * Updates this transformation to be the composition - * of a given {@link AffineTransformation} with this transformation. - * This produces a transformation whose effect - * is equal to applying the argument transformation - * followed by this transformation. - * Mathematically, - *
                  -   * A.composeBefore(B) = TA x TB
                  -   * 
                  - * - * @param trans an affine transformation - * @return this transformation, with an updated matrix - */ - public AffineTransformation composeBefore(AffineTransformation trans) - { - double mp00 = m00 * trans.m00 + m01 * trans.m10; - double mp01 = m00 * trans.m01 + m01 * trans.m11; - double mp02 = m00 * trans.m02 + m01 * trans.m12 + m02; - double mp10 = m10 * trans.m00 + m11 * trans.m10; - double mp11 = m10 * trans.m01 + m11 * trans.m11; - double mp12 = m10 * trans.m02 + m11 * trans.m12 + m12; - m00 = mp00; - m01 = mp01; - m02 = mp02; - m10 = mp10; - m11 = mp11; - m12 = mp12; - return this; - } - - /** - * Applies this transformation to the src coordinate - * and places the results in the dest coordinate - * (which may be the same as the source). - * - * @param src the coordinate to transform - * @param dest the coordinate to accept the results - * @return the dest coordinate - */ - public Coordinate transform(Coordinate src, Coordinate dest) - { - double xp = m00 * src.x + m01 * src.y + m02; - double yp = m10 * src.x + m11 * src.y + m12; - dest.x = xp; - dest.y = yp; - return dest; - } - - /** - * Cretaes a new @link Geometry which is the result - * of this transformation applied to the input Geometry. - * - *@param seq a Geometry - *@return a transformed Geometry - */ - public Geometry transform(Geometry g) - { - Geometry g2 = (Geometry) g.clone(); - g2.apply(this); - return g2; - } - - /** - * Applies this transformation to the i'th coordinate - * in the given CoordinateSequence. - * - *@param seq a CoordinateSequence - *@param i the index of the coordinate to transform - */ - public void transform(CoordinateSequence seq, int i) - { - double xp = m00 * seq.getOrdinate(i, 0) + m01 * seq.getOrdinate(i, 1) + m02; - double yp = m10 * seq.getOrdinate(i, 0) + m11 * seq.getOrdinate(i, 1) + m12; - seq.setOrdinate(i, 0, xp); - seq.setOrdinate(i, 1, yp); - } - - /** - * Transforms the i'th coordinate in the input sequence - * - *@param seq a CoordinateSequence - *@param i the index of the coordinate to transform - */ - public void filter(CoordinateSequence seq, int i) - { - transform(seq, i); - } - - public boolean isGeometryChanged() - { - return true; - } - - /** - * Reports that this filter should continue to be executed until - * all coordinates have been transformed. - * - * @return false - */ - public boolean isDone() - { - return false; - } - - /** - * Tests if this transformation is the identity transformation. - * - * @return true if this is the identity transformation - */ - public boolean isIdentity() - { - return (m00 == 1 && m01 == 0 && m02 == 0 - && m10 == 0 && m11 == 1 && m12 == 0); - } - - /** - * Tests if an object is an - * AffineTransformation - * and has the same matrix as - * this transformation. - * - * @param obj an object to test - * @return true if the given object is equal to this object - */ - public boolean equals(Object obj) - { - if (obj == null) return false; - if (! (obj instanceof AffineTransformation)) - return false; - - AffineTransformation trans = (AffineTransformation) obj; - return m00 == trans.m00 - && m01 == trans.m01 - && m02 == trans.m02 - && m10 == trans.m10 - && m11 == trans.m11 - && m12 == trans.m12; - } - - /** - * Gets a text representation of this transformation. - * The string is of the form: - *
                  -   * AffineTransformation[[m00, m01, m02], [m10, m11, m12]]
                  -   * 
                  - * - * @return a string representing this transformation - * - */ - public String toString() - { - return "AffineTransformation[[" + m00 + ", " + m01 + ", " + m02 - + "], [" - + m10 + ", " + m11 + ", " + m12 + "]]"; - } - - /** - * Clones this transformation - * - * @return a copy of this transformation - */ - public Object clone() - { - try { - return super.clone(); - } catch(Exception ex) { - Assert.shouldNeverReachHere(); - } - return null; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java b/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java deleted file mode 100644 index 2ce84cb1b4..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java +++ /dev/null @@ -1,165 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.math.Matrix; -import com.vividsolutions.jts.algorithm.*; - -/** - * Builds an {@link AffineTransformation} defined by a set of control vectors. - * A control vector consists of a source point and a destination point, - * which is the image of the source point under the desired transformation. - *

                  - * A transformation is well-defined - * by a set of three control vectors - * if and only if the source points are not collinear. - * (In particular, the degenerate situation - * where two or more source points are identical will not produce a well-defined transformation). - * A well-defined transformation exists and is unique. - * If the control vectors are not well-defined, the system of equations - * defining the transformation matrix entries is not solvable, - * and no transformation can be determined. - *

                  - * No such restriction applies to the destination points. - * However, if the destination points are collinear or non-unique, - * a non-invertible transformations will be generated. - *

                  - * This technique of recovering a transformation - * from its effect on known points is used in the Bilinear Interpolated Triangulation - * algorithm for warping planar surfaces. - * - * @author Martin Davis - */ -public class AffineTransformationBuilder -{ - private Coordinate src0; - private Coordinate src1; - private Coordinate src2; - private Coordinate dest0; - private Coordinate dest1; - private Coordinate dest2; - - // the matrix entries for the transformation - private double m00, m01, m02, m10, m11, m12; - - - /** - * Constructs a new builder for - * the transformation defined by the given - * set of control point mappings. - * - * @param src0 a control point - * @param src1 a control point - * @param src2 a control point - * @param dest0 the image of control point 0 under the required transformation - * @param dest1 the image of control point 1 under the required transformation - * @param dest2 the image of control point 2 under the required transformation - */ - public AffineTransformationBuilder(Coordinate src0, - Coordinate src1, - Coordinate src2, - Coordinate dest0, - Coordinate dest1, - Coordinate dest2) - { - this.src0 = src0; - this.src1 = src1; - this.src2 = src2; - this.dest0 = dest0; - this.dest1 = dest1; - this.dest2 = dest2; - } - - /** - * Computes the {@link AffineTransformation} - * determined by the control point mappings, - * or null if the control vectors do not determine a well-defined transformation. - * - * @return an affine transformation - * @return null if the control vectors do not determine a well-defined transformation - */ - public AffineTransformation getTransformation() - { - // compute full 3-point transformation - boolean isSolvable = compute(); - if (isSolvable) - return new AffineTransformation(m00, m01, m02, m10, m11, m12); - return null; - } - - /** - * Computes the transformation matrix by - * solving the two systems of linear equations - * defined by the control point mappings, - * if this is possible. - * - * @return true if the transformation matrix is solvable - */ - private boolean compute() - { - double[] bx = new double[] { dest0.x, dest1.x, dest2.x }; - double[] row0 = solve(bx); - if (row0 == null) return false; - m00 = row0[0]; - m01 = row0[1]; - m02 = row0[2]; - - double[] by = new double[] { dest0.y, dest1.y, dest2.y }; - double[] row1 = solve(by); - if (row1 == null) return false; - m10 = row1[0]; - m11 = row1[1]; - m12 = row1[2]; - return true; - } - - /** - * Solves the transformation matrix system of linear equations - * for the given right-hand side vector. - * - * @param b the vector for the right-hand side of the system - * @return the solution vector - * @return null if no solution could be determined - */ - private double[] solve(double[] b) - { - double[][] a = new double[][] { - { src0.x, src0.y, 1 }, - { src1.x, src1.y, 1}, - { src2.x, src2.y, 1} - }; - return Matrix.solve(a, b); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationFactory.java b/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationFactory.java deleted file mode 100644 index d57aa7b09d..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/AffineTransformationFactory.java +++ /dev/null @@ -1,199 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.algorithm.Angle; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Supports creating {@link AffineTransformation}s defined by various kinds of - * inputs and transformation mapping rules. - * - * @author Martin Davis - * - */ -public class AffineTransformationFactory { - /** - * Creates a tranformation from a set of three control vectors. A control - * vector consists of a source point and a destination point, which is the - * image of the source point under the desired transformation. Three control - * vectors allows defining a fully general affine transformation. - * - * @param src0 - * @param src1 - * @param src2 - * @param dest0 - * @param dest1 - * @param dest2 - * @return the computed transformation - */ - public static AffineTransformation createFromControlVectors(Coordinate src0, - Coordinate src1, Coordinate src2, Coordinate dest0, Coordinate dest1, - Coordinate dest2) { - AffineTransformationBuilder builder = new AffineTransformationBuilder(src0, - src1, src2, dest0, dest1, dest2); - return builder.getTransformation(); - } - - /** - * Creates an AffineTransformation defined by a pair of control vectors. A - * control vector consists of a source point and a destination point, which is - * the image of the source point under the desired transformation. The - * computed transformation is a combination of one or more of a uniform scale, - * a rotation, and a translation (i.e. there is no shear component and no - * reflection) - * - * @param src0 - * @param src1 - * @param dest0 - * @param dest1 - * @return the computed transformation - * @return null if the control vectors do not determine a well-defined transformation - */ - public static AffineTransformation createFromControlVectors(Coordinate src0, - Coordinate src1, Coordinate dest0, Coordinate dest1) { - Coordinate rotPt = new Coordinate(dest1.x - dest0.x, dest1.y - dest0.y); - - double ang = Angle.angleBetweenOriented(src1, src0, rotPt); - - double srcDist = src1.distance(src0); - double destDist = dest1.distance(dest0); - - if (srcDist == 0.0) - return null; - - double scale = destDist / srcDist; - - AffineTransformation trans = AffineTransformation.translationInstance( - -src0.x, -src0.y); - trans.rotate(ang); - trans.scale(scale, scale); - trans.translate(dest0.x, dest0.y); - return trans; - } - - /** - * Creates an AffineTransformation defined by a single control vector. A - * control vector consists of a source point and a destination point, which is - * the image of the source point under the desired transformation. This - * produces a translation. - * - * @param src0 - * the start point of the control vector - * @param dest0 - * the end point of the control vector - * @return the computed transformation - */ - public static AffineTransformation createFromControlVectors(Coordinate src0, - Coordinate dest0) { - double dx = dest0.x - src0.x; - double dy = dest0.y - src0.y; - return AffineTransformation.translationInstance(dx, dy); - } - - /** - * Creates an AffineTransformation defined by a set of control vectors. - * Between one and three vectors must be supplied. - * - * @param src - * the source points of the vectors - * @param dest - * the destination points of the vectors - * @return the computed transformation - * @throws IllegalArgumentException - * if the control vector arrays are too short, long or of different - * lengths - */ - public static AffineTransformation createFromControlVectors(Coordinate[] src, - Coordinate[] dest) { - if (src.length != dest.length) - throw new IllegalArgumentException( - "Src and Dest arrays are not the same length"); - if (src.length <= 0) - throw new IllegalArgumentException("Too few control points"); - if (src.length > 3) - throw new IllegalArgumentException("Too many control points"); - - if (src.length == 1) - return createFromControlVectors(src[0], dest[0]); - if (src.length == 2) - return createFromControlVectors(src[0], src[1], dest[0], dest[1]); - - return createFromControlVectors(src[0], src[1], src[2], dest[0], dest[1], - dest[2]); - } - - /** - * Creates an AffineTransformation defined by a maping between two baselines. - * The computed transformation consists of: - *

                    - *
                  • a translation - * from the start point of the source baseline to the start point of the destination baseline, - *
                  • a rotation through the angle between the baselines about the destination start point, - *
                  • and a scaling equal to the ratio of the baseline lengths. - *
                  - * If the source baseline has zero length, an identity transformation is returned. - * - * @param src0 the start point of the source baseline - * @param src1 the end point of the source baseline - * @param dest0 the start point of the destination baseline - * @param dest1 the end point of the destination baseline - * @return the computed transformation - */ - public static AffineTransformation createFromBaseLines( - Coordinate src0, Coordinate src1, - Coordinate dest0, Coordinate dest1) - { - Coordinate rotPt = new Coordinate(src0.x + dest1.x - dest0.x, src0.y + dest1.y - dest0.y); - - double ang = Angle.angleBetweenOriented(src1, src0, rotPt); - - double srcDist = src1.distance(src0); - double destDist = dest1.distance(dest0); - - // return identity if transformation would be degenerate - if (srcDist == 0.0) - return new AffineTransformation(); - - double scale = destDist / srcDist; - - AffineTransformation trans = AffineTransformation.translationInstance( - -src0.x, -src0.y); - trans.rotate(ang); - trans.scale(scale, scale); - trans.translate(dest0.x, dest0.y); - return trans; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java deleted file mode 100644 index 9e3cca752f..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java +++ /dev/null @@ -1,83 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Extracts a single representative {@link Coordinate} - * from each connected component of a {@link Geometry}. - * - * @version 1.9 - */ -public class ComponentCoordinateExtracter - implements GeometryComponentFilter -{ - - /** - * Extracts the linear components from a single geometry. - * If more than one geometry is to be processed, it is more - * efficient to create a single {@link ComponentCoordinateExtracter} instance - * and pass it to multiple geometries. - * - * @param geom the Geometry from which to extract - * @return a list of Coordinates - */ - public static List getCoordinates(Geometry geom) - { - List coords = new ArrayList(); - geom.apply(new ComponentCoordinateExtracter(coords)); - return coords; - } - - private List coords; - - /** - * Constructs a LineExtracterFilter with a list in which to store LineStrings found. - */ - public ComponentCoordinateExtracter(List coords) - { - this.coords = coords; - } - - public void filter(Geometry geom) - { - // add coordinates from connected components - if (geom instanceof LineString - || geom instanceof Point) - coords.add(geom.getCoordinate()); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java deleted file mode 100644 index 078fa77e0a..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java +++ /dev/null @@ -1,73 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.GeometryMapper.MapOp; - -/** - * Maps the members of a {@link GeometryCollection} - * into another GeometryCollection via a defined - * mapping function. - * - * @author Martin Davis - * - */ -public class GeometryCollectionMapper -{ - public static GeometryCollection map(GeometryCollection gc, MapOp op) - { - GeometryCollectionMapper mapper = new GeometryCollectionMapper(op); - return mapper.map(gc); - } - - private MapOp mapOp = null; - - public GeometryCollectionMapper(MapOp mapOp) { - this.mapOp = mapOp; - } - - public GeometryCollection map(GeometryCollection gc) - { - List mapped = new ArrayList(); - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = mapOp.map(gc.getGeometryN(i)); - if (!g.isEmpty()) - mapped.add(g); - } - return gc.getFactory().createGeometryCollection( - GeometryFactory.toGeometryArray(mapped)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryCombiner.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryCombiner.java deleted file mode 100644 index 96dc14089f..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryCombiner.java +++ /dev/null @@ -1,189 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; - -/** - * Combines {@link Geometry}s - * to produce a {@link GeometryCollection} of the most appropriate type. - * Input geometries which are already collections - * will have their elements extracted first. - * No validation of the result geometry is performed. - * (The only case where invalidity is possible is where {@link Polygonal} geometries - * are combined and result in a self-intersection). - * - * @author mbdavis - * @see GeometryFactory#buildGeometry - */ -public class GeometryCombiner -{ - /** - * Combines a collection of geometries. - * - * @param geoms the geometries to combine - * @return the combined geometry - */ - public static Geometry combine(Collection geoms) - { - GeometryCombiner combiner = new GeometryCombiner(geoms); - return combiner.combine(); - } - - /** - * Combines two geometries. - * - * @param g0 a geometry to combine - * @param g1 a geometry to combine - * @return the combined geometry - */ - public static Geometry combine(Geometry g0, Geometry g1) - { - GeometryCombiner combiner = new GeometryCombiner(createList(g0, g1)); - return combiner.combine(); - } - - /** - * Combines three geometries. - * - * @param g0 a geometry to combine - * @param g1 a geometry to combine - * @param g2 a geometry to combine - * @return the combined geometry - */ - public static Geometry combine(Geometry g0, Geometry g1, Geometry g2) - { - GeometryCombiner combiner = new GeometryCombiner(createList(g0, g1, g2)); - return combiner.combine(); - } - - /** - * Creates a list from two items - * - * @param obj0 - * @param obj1 - * @return a List containing the two items - */ - private static List createList(Object obj0, Object obj1) - { - List list = new ArrayList(); - list.add(obj0); - list.add(obj1); - return list; - } - - /** - * Creates a list from two items - * - * @param obj0 - * @param obj1 - * @return a List containing the two items - */ - private static List createList(Object obj0, Object obj1, Object obj2) - { - List list = new ArrayList(); - list.add(obj0); - list.add(obj1); - list.add(obj2); - return list; - } - - private GeometryFactory geomFactory; - private boolean skipEmpty = false; - private Collection inputGeoms; - - /** - * Creates a new combiner for a collection of geometries - * - * @param geoms the geometries to combine - */ - public GeometryCombiner(Collection geoms) - { - geomFactory = extractFactory(geoms); - this.inputGeoms = geoms; - } - - /** - * Extracts the GeometryFactory used by the geometries in a collection - * - * @param geoms - * @return a GeometryFactory - */ - public static GeometryFactory extractFactory(Collection geoms) { - if (geoms.isEmpty()) - return null; - return ((Geometry) geoms.iterator().next()).getFactory(); - } - - /** - * Computes the combination of the input geometries - * to produce the most appropriate {@link Geometry} or {@link GeometryCollection} - * - * @return a Geometry which is the combination of the inputs - */ - public Geometry combine() - { - List elems = new ArrayList(); - for (Iterator i = inputGeoms.iterator(); i.hasNext(); ) { - Geometry g = (Geometry) i.next(); - extractElements(g, elems); - } - - if (elems.size() == 0) { - if (geomFactory != null) { - // return an empty GC - return geomFactory.createGeometryCollection(null); - } - return null; - } - // return the "simplest possible" geometry - return geomFactory.buildGeometry(elems); - } - - private void extractElements(Geometry geom, List elems) - { - if (geom == null) - return; - - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry elemGeom = geom.getGeometryN(i); - if (skipEmpty && elemGeom.isEmpty()) - continue; - elems.add(elemGeom); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryEditor.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryEditor.java deleted file mode 100644 index d625b314d2..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryEditor.java +++ /dev/null @@ -1,365 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -import java.util.ArrayList; - - -/** - * A class which supports creating new {@link Geometry}s - * which are modifications of existing ones, - * maintaining the same type structure. - * Geometry objects are intended to be treated as immutable. - * This class "modifies" Geometrys - * by traversing them, applying a user-defined - * {@link GeometryEditorOperation}, {@link CoordinateSequenceOperation} or {@link CoordinateOperation} - * and creating new Geometrys with the same structure but - * (possibly) modified components. - *

                  - * Examples of the kinds of modifications which can be made are: - *

                    - *
                  • the values of the coordinates may be changed. - * The editor does not check whether changing coordinate values makes the result Geometry invalid - *
                  • the coordinate lists may be changed - * (e.g. by adding, deleting or modifying coordinates). - * The modifed coordinate lists must be consistent with their original parent component - * (e.g. a LinearRing must always have at least 4 coordinates, and the first and last - * coordinate must be equal) - *
                  • components of the original geometry may be deleted - * (e.g. holes may be removed from a Polygon, or LineStrings removed from a MultiLineString). - * Deletions will be propagated up the component tree appropriately. - *
                  - * All changes must be consistent with the original Geometry's structure - * (e.g. a Polygon cannot be collapsed into a LineString). - * If changing the structure is required, use a {@link GeometryTransformer}. - *

                  - * This class supports creating an edited Geometry - * using a different GeometryFactory via the {@link #GeometryEditor(GeometryFactory)} - * constructor. - * Examples of situations where this is required is if the geometry is - * transformed to a new SRID and/or a new PrecisionModel. - *

                  - * Usage Notes - *

                    - *
                  • The resulting Geometry is not checked for validity. - * If validity needs to be enforced, the new Geometry's - * {@link Geometry#isValid} method should be called. - *
                  • By default the UserData of the input geometry is not copied to the result. - *
                  - * - * @see GeometryTransformer - * @see Geometry#isValid - * - * @version 1.7 - */ -public class GeometryEditor -{ - /** - * The factory used to create the modified Geometry. - * If null the GeometryFactory of the input is used. - */ - private GeometryFactory factory = null; - private boolean isUserDataCopied = false; - - /** - * Creates a new GeometryEditor object which will create - * edited {@link Geometry}s with the same {@link GeometryFactory} as the input Geometry. - */ - public GeometryEditor() - { - } - - /** - * Creates a new GeometryEditor object which will create - * edited {@link Geometry}s with the given {@link GeometryFactory}. - * - * @param factory the GeometryFactory to create edited Geometrys with - */ - public GeometryEditor(GeometryFactory factory) - { - this.factory = factory; - } - - /** - * Sets whether the User Data is copied to the edit result. - * Only the object reference is copied. - * - * @param isUserDataCopied true if the input user data should be copied. - */ - public void setCopyUserData(boolean isUserDataCopied) - { - this.isUserDataCopied = isUserDataCopied; - } - - /** - * Edit the input {@link Geometry} with the given edit operation. - * Clients can create subclasses of {@link GeometryEditorOperation} or - * {@link CoordinateOperation} to perform required modifications. - * - * @param geometry the Geometry to edit - * @param operation the edit operation to carry out - * @return a new {@link Geometry} which is the result of the editing (which may be empty) - */ - public Geometry edit(Geometry geometry, GeometryEditorOperation operation) - { - // nothing to do - if (geometry == null) return null; - - Geometry result = editInternal(geometry, operation); - if (isUserDataCopied) { - result.setUserData(geometry.getUserData()); - } - return result; - } - - private Geometry editInternal(Geometry geometry, GeometryEditorOperation operation) - { - // if client did not supply a GeometryFactory, use the one from the input Geometry - if (factory == null) - factory = geometry.getFactory(); - - if (geometry instanceof GeometryCollection) { - return editGeometryCollection((GeometryCollection) geometry, - operation); - } - - if (geometry instanceof Polygon) { - return editPolygon((Polygon) geometry, operation); - } - - if (geometry instanceof Point) { - return operation.edit(geometry, factory); - } - - if (geometry instanceof LineString) { - return operation.edit(geometry, factory); - } - - Assert.shouldNeverReachHere("Unsupported Geometry class: " + geometry.getClass().getName()); - return null; - } - - private Polygon editPolygon(Polygon polygon, - GeometryEditorOperation operation) { - Polygon newPolygon = (Polygon) operation.edit(polygon, factory); - // create one if needed - if (newPolygon == null) - newPolygon = factory.createPolygon((CoordinateSequence) null); - if (newPolygon.isEmpty()) { - //RemoveSelectedPlugIn relies on this behaviour. [Jon Aquino] - return newPolygon; - } - - LinearRing shell = (LinearRing) edit(newPolygon.getExteriorRing(), operation); - if (shell == null || shell.isEmpty()) { - //RemoveSelectedPlugIn relies on this behaviour. [Jon Aquino] - return factory.createPolygon(null, null); - } - - ArrayList holes = new ArrayList(); - for (int i = 0; i < newPolygon.getNumInteriorRing(); i++) { - LinearRing hole = (LinearRing) edit(newPolygon.getInteriorRingN(i), operation); - if (hole == null || hole.isEmpty()) { - continue; - } - holes.add(hole); - } - - return factory.createPolygon(shell, - (LinearRing[]) holes.toArray(new LinearRing[] { })); - } - - private GeometryCollection editGeometryCollection( - GeometryCollection collection, GeometryEditorOperation operation) { - // first edit the entire collection - // MD - not sure why this is done - could just check original collection? - GeometryCollection collectionForType = (GeometryCollection) operation.edit(collection, - factory); - - // edit the component geometries - ArrayList geometries = new ArrayList(); - for (int i = 0; i < collectionForType.getNumGeometries(); i++) { - Geometry geometry = edit(collectionForType.getGeometryN(i), operation); - if (geometry == null || geometry.isEmpty()) { - continue; - } - geometries.add(geometry); - } - - if (collectionForType.getClass() == MultiPoint.class) { - return factory.createMultiPoint((Point[]) geometries.toArray( - new Point[] { })); - } - if (collectionForType.getClass() == MultiLineString.class) { - return factory.createMultiLineString((LineString[]) geometries.toArray( - new LineString[] { })); - } - if (collectionForType.getClass() == MultiPolygon.class) { - return factory.createMultiPolygon((Polygon[]) geometries.toArray( - new Polygon[] { })); - } - return factory.createGeometryCollection((Geometry[]) geometries.toArray( - new Geometry[] { })); - } - - /** - * A interface which specifies an edit operation for Geometries. - * - * @version 1.7 - */ - public interface GeometryEditorOperation - { - /** - * Edits a Geometry by returning a new Geometry with a modification. - * The returned geometry may be: - *
                    - *
                  • the input geometry itself - * The returned Geometry might be the same as the Geometry passed in. - * It may be null if the geometry is to be deleted. - * - * @param geometry the Geometry to modify - * @param factory the factory with which to construct the modified Geometry - * (may be different to the factory of the input geometry) - * @return a new Geometry which is a modification of the input Geometry - * @return null if the Geometry is to be deleted completely - */ - Geometry edit(Geometry geometry, GeometryFactory factory); - } - - /** - * A GeometryEditorOperation which does not modify - * the input geometry. - * This can be used for simple changes of - * GeometryFactory (including PrecisionModel and SRID). - * - * @author mbdavis - * - */ - public static class NoOpGeometryOperation - implements GeometryEditorOperation - { - public Geometry edit(Geometry geometry, GeometryFactory factory) - { - return geometry; - } - } - - /** - * A {@link GeometryEditorOperation} which edits the coordinate list of a {@link Geometry}. - * Operates on Geometry subclasses which contains a single coordinate list. - */ - public abstract static class CoordinateOperation - implements GeometryEditorOperation - { - public final Geometry edit(Geometry geometry, GeometryFactory factory) { - if (geometry instanceof LinearRing) { - return factory.createLinearRing(edit(geometry.getCoordinates(), - geometry)); - } - - if (geometry instanceof LineString) { - return factory.createLineString(edit(geometry.getCoordinates(), - geometry)); - } - - if (geometry instanceof Point) { - Coordinate[] newCoordinates = edit(geometry.getCoordinates(), - geometry); - - return factory.createPoint((newCoordinates.length > 0) - ? newCoordinates[0] : null); - } - - return geometry; - } - - /** - * Edits the array of {@link Coordinate}s from a {@link Geometry}. - *

                    - * If it is desired to preserve the immutability of Geometrys, - * if the coordinates are changed a new array should be created - * and returned. - * - * @param coordinates the coordinate array to operate on - * @param geometry the geometry containing the coordinate list - * @return an edited coordinate array (which may be the same as the input) - */ - public abstract Coordinate[] edit(Coordinate[] coordinates, - Geometry geometry); - } - - /** - * A {@link GeometryEditorOperation} which edits the {@link CoordinateSequence} - * of a {@link Geometry}. - * Operates on Geometry subclasses which contains a single coordinate list. - */ - public abstract static class CoordinateSequenceOperation - implements GeometryEditorOperation - { - public final Geometry edit(Geometry geometry, GeometryFactory factory) { - if (geometry instanceof LinearRing) { - return factory.createLinearRing(edit( - ((LinearRing)geometry).getCoordinateSequence(), - geometry)); - } - - if (geometry instanceof LineString) { - return factory.createLineString(edit( - ((LineString)geometry).getCoordinateSequence(), - geometry)); - } - - if (geometry instanceof Point) { - return factory.createPoint(edit( - ((Point)geometry).getCoordinateSequence(), - geometry)); - } - - return geometry; - } - - /** - * Edits a {@link CoordinateSequence} from a {@link Geometry}. - * - * @param coordseq the coordinate array to operate on - * @param geometry the geometry containing the coordinate list - * @return an edited coordinate sequence (which may be the same as the input) - */ - public abstract CoordinateSequence edit(CoordinateSequence coordSeq, - Geometry geometry); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryExtracter.java deleted file mode 100644 index 5fb05b1854..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryExtracter.java +++ /dev/null @@ -1,105 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Extracts the components of a given type from a {@link Geometry}. - * - * @version 1.7 - */ -public class GeometryExtracter - implements GeometryFilter -{ - - protected static boolean isOfClass(Object o, Class clz) - { - return clz.isAssignableFrom(o.getClass()); -// return o.getClass() == clz; - } - - /** - * Extracts the components of type clz from a {@link Geometry} - * and adds them to the provided {@link List}. - * - * @param geom the geometry from which to extract - * @param list the list to add the extracted elements to - */ - public static List extract(Geometry geom, Class clz, List list) - { - if (isOfClass(geom, clz)) { - list.add(geom); - } - else if (geom instanceof GeometryCollection) { - geom.apply(new GeometryExtracter(clz, list)); - } - // skip non-LineString elemental geometries - - return list; - } - - /** - * Extracts the components of type clz from a {@link Geometry} - * and returns them in a {@link List}. - * - * @param geom the geometry from which to extract - */ - public static List extract(Geometry geom, Class clz) - { - return extract(geom, clz, new ArrayList()); - } - - private Class clz; - private List comps; - - /** - * Constructs a filter with a list in which to store the elements found. - * - * @param clz the class of the components to extract (null means all types) - * @param comps the list to extract into - */ - public GeometryExtracter(Class clz, List comps) - { - this.clz = clz; - this.comps = comps; - } - - public void filter(Geometry geom) - { - if (clz == null || isOfClass(geom, clz)) comps.add(geom); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryMapper.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryMapper.java deleted file mode 100644 index 260909fb55..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryMapper.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Methods to map various collections - * of {@link Geometry}s - * via defined mapping functions. - * - * @author Martin Davis - * - */ -public class GeometryMapper -{ - /** - * Maps the members of a {@link Geometry} - * (which may be atomic or composite) - * into another Geometry of most specific type. - * null results are skipped. - * In the case of hierarchical {@link GeometryCollection}s, - * only the first level of members are mapped. - * - * @param geom the input atomic or composite geometry - * @param op the mapping operation - * @return a result collection or geometry of most specific type - */ - public static Geometry map(Geometry geom, MapOp op) - { - List mapped = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry g = op.map(geom.getGeometryN(i)); - if (g != null) - mapped.add(g); - } - return geom.getFactory().buildGeometry(mapped); - } - - public static Collection map(Collection geoms, MapOp op) - { - List mapped = new ArrayList(); - for (Iterator i = geoms.iterator(); i.hasNext(); ) { - Geometry g = (Geometry) i.next(); - Geometry gr = op.map(g); - if (gr != null) - mapped.add(gr); - } - return mapped; - } - - /** - * An interface for geometry functions used for mapping. - * - * @author Martin Davis - * - */ - public interface MapOp - { - /** - * Computes a new geometry value. - * - * @param g the input geometry - * @return a result geometry - */ - Geometry map(Geometry g); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/GeometryTransformer.java b/src/main/java/com/vividsolutions/jts/geom/util/GeometryTransformer.java deleted file mode 100644 index 25828d5f86..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/GeometryTransformer.java +++ /dev/null @@ -1,306 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * A framework for processes which transform an input {@link Geometry} into - * an output {@link Geometry}, possibly changing its structure and type(s). - * This class is a framework for implementing subclasses - * which perform transformations on - * various different Geometry subclasses. - * It provides an easy way of applying specific transformations - * to given geometry types, while allowing unhandled types to be simply copied. - * Also, the framework ensures that if subcomponents change type - * the parent geometries types change appropriately to maintain valid structure. - * Subclasses will override whichever transformX methods - * they need to to handle particular Geometry types. - *

                    - * A typically usage would be a transformation class that transforms Polygons into - * Polygons, LineStrings or Points, depending on the geometry of the input - * (For instance, a simplification operation). - * This class would likely need to override the {@link #transformMultiPolygon(MultiPolygon, Geometry)transformMultiPolygon} - * method to ensure that if input Polygons change type the result is a GeometryCollection, - * not a MultiPolygon. - *

                    - * The default behaviour of this class is simply to recursively transform - * each Geometry component into an identical object by deep copying down - * to the level of, but not including, coordinates. - *

                    - * All transformX methods may return null, - * to avoid creating empty or invalid geometry objects. This will be handled correctly - * by the transformer. transformXXX methods should always return valid - * geometry - if they cannot do this they should return null - * (for instance, it may not be possible for a transformLineString implementation - * to return at least two points - in this case, it should return null). - * The {@link #transform(Geometry)transform} method itself will always - * return a non-null Geometry object (but this may be empty). - * - * @version 1.7 - * - * @see GeometryEditor - */ -public class GeometryTransformer -{ - - /** - * Possible extensions: - * getParent() method to return immediate parent e.g. of LinearRings in Polygons - */ - - private Geometry inputGeom; - - protected GeometryFactory factory = null; - - // these could eventually be exposed to clients - /** - * true if empty geometries should not be included in the result - */ - private boolean pruneEmptyGeometry = true; - - /** - * true if a homogenous collection result - * from a {@link GeometryCollection} should still - * be a general GeometryCollection - */ - private boolean preserveGeometryCollectionType = true; - - /** - * true if the output from a collection argument should still be a collection - */ - private boolean preserveCollections = false; - - /** - * true if the type of the input should be preserved - */ - private boolean preserveType = false; - - public GeometryTransformer() { - } - - /** - * Utility function to make input geometry available - * - * @return the input geometry - */ - public Geometry getInputGeometry() { return inputGeom; } - - public final Geometry transform(Geometry inputGeom) - { - this.inputGeom = inputGeom; - this.factory = inputGeom.getFactory(); - - if (inputGeom instanceof Point) - return transformPoint((Point) inputGeom, null); - if (inputGeom instanceof MultiPoint) - return transformMultiPoint((MultiPoint) inputGeom, null); - if (inputGeom instanceof LinearRing) - return transformLinearRing((LinearRing) inputGeom, null); - if (inputGeom instanceof LineString) - return transformLineString((LineString) inputGeom, null); - if (inputGeom instanceof MultiLineString) - return transformMultiLineString((MultiLineString) inputGeom, null); - if (inputGeom instanceof Polygon) - return transformPolygon((Polygon) inputGeom, null); - if (inputGeom instanceof MultiPolygon) - return transformMultiPolygon((MultiPolygon) inputGeom, null); - if (inputGeom instanceof GeometryCollection) - return transformGeometryCollection((GeometryCollection) inputGeom, null); - - throw new IllegalArgumentException("Unknown Geometry subtype: " + inputGeom.getClass().getName()); - } - - /** - * Convenience method which provides standard way of - * creating a {@link CoordinateSequence} - * - * @param coords the coordinate array to copy - * @return a coordinate sequence for the array - */ - protected final CoordinateSequence createCoordinateSequence(Coordinate[] coords) - { - return factory.getCoordinateSequenceFactory().create(coords); - } - - /** - * Convenience method which provides statndard way of copying {@link CoordinateSequence}s - * @param seq the sequence to copy - * @return a deep copy of the sequence - */ - protected final CoordinateSequence copy(CoordinateSequence seq) - { - return (CoordinateSequence) seq.clone(); - } - - /** - * Transforms a {@link CoordinateSequence}. - * This method should always return a valid coordinate list for - * the desired result type. (E.g. a coordinate list for a LineString - * must have 0 or at least 2 points). - * If this is not possible, return an empty sequence - - * this will be pruned out. - * - * @param coords the coordinates to transform - * @param parent the parent geometry - * @return the transformed coordinates - */ - protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) - { - return copy(coords); - } - - protected Geometry transformPoint(Point geom, Geometry parent) { - return factory.createPoint( - transformCoordinates(geom.getCoordinateSequence(), geom)); - } - - protected Geometry transformMultiPoint(MultiPoint geom, Geometry parent) { - List transGeomList = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry transformGeom = transformPoint((Point) geom.getGeometryN(i), geom); - if (transformGeom == null) continue; - if (transformGeom.isEmpty()) continue; - transGeomList.add(transformGeom); - } - return factory.buildGeometry(transGeomList); - } - - /** - * Transforms a LinearRing. - * The transformation of a LinearRing may result in a coordinate sequence - * which does not form a structurally valid ring (i.e. a degnerate ring of 3 or fewer points). - * In this case a LineString is returned. - * Subclasses may wish to override this method and check for this situation - * (e.g. a subclass may choose to eliminate degenerate linear rings) - * - * @param geom the ring to simplify - * @param parent the parent geometry - * @return a LinearRing if the transformation resulted in a structurally valid ring - * @return a LineString if the transformation caused the LinearRing to collapse to 3 or fewer points - */ - protected Geometry transformLinearRing(LinearRing geom, Geometry parent) { - CoordinateSequence seq = transformCoordinates(geom.getCoordinateSequence(), geom); - if (seq == null) - return factory.createLinearRing((CoordinateSequence) null); - int seqSize = seq.size(); - // ensure a valid LinearRing - if (seqSize > 0 && seqSize < 4 && ! preserveType) - return factory.createLineString(seq); - return factory.createLinearRing(seq); - } - - /** - * Transforms a {@link LineString} geometry. - * - * @param geom - * @param parent - * @return - */ - protected Geometry transformLineString(LineString geom, Geometry parent) { - // should check for 1-point sequences and downgrade them to points - return factory.createLineString( - transformCoordinates(geom.getCoordinateSequence(), geom)); - } - - protected Geometry transformMultiLineString(MultiLineString geom, Geometry parent) { - List transGeomList = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry transformGeom = transformLineString((LineString) geom.getGeometryN(i), geom); - if (transformGeom == null) continue; - if (transformGeom.isEmpty()) continue; - transGeomList.add(transformGeom); - } - return factory.buildGeometry(transGeomList); - } - - protected Geometry transformPolygon(Polygon geom, Geometry parent) { - boolean isAllValidLinearRings = true; - Geometry shell = transformLinearRing((LinearRing) geom.getExteriorRing(), geom); - - if (shell == null - || ! (shell instanceof LinearRing) - || shell.isEmpty() ) - isAllValidLinearRings = false; -//return factory.createPolygon(null, null); - - ArrayList holes = new ArrayList(); - for (int i = 0; i < geom.getNumInteriorRing(); i++) { - Geometry hole = transformLinearRing((LinearRing) geom.getInteriorRingN(i), geom); - if (hole == null || hole.isEmpty()) { - continue; - } - if (! (hole instanceof LinearRing)) - isAllValidLinearRings = false; - - holes.add(hole); - } - - if (isAllValidLinearRings) - return factory.createPolygon((LinearRing) shell, - (LinearRing[]) holes.toArray(new LinearRing[] { })); - else { - List components = new ArrayList(); - if (shell != null) components.add(shell); - components.addAll(holes); - return factory.buildGeometry(components); - } - } - - protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) { - List transGeomList = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry transformGeom = transformPolygon((Polygon) geom.getGeometryN(i), geom); - if (transformGeom == null) continue; - if (transformGeom.isEmpty()) continue; - transGeomList.add(transformGeom); - } - return factory.buildGeometry(transGeomList); - } - - protected Geometry transformGeometryCollection(GeometryCollection geom, Geometry parent) { - List transGeomList = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry transformGeom = transform(geom.getGeometryN(i)); - if (transformGeom == null) continue; - if (pruneEmptyGeometry && transformGeom.isEmpty()) continue; - transGeomList.add(transformGeom); - } - if (preserveGeometryCollectionType) - return factory.createGeometryCollection(GeometryFactory.toGeometryArray(transGeomList)); - return factory.buildGeometry(transGeomList); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/LineStringExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/LineStringExtracter.java deleted file mode 100644 index 8b5bc31fbd..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/LineStringExtracter.java +++ /dev/null @@ -1,108 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Extracts all the {@link LineString} elements from a {@link Geometry}. - * - * @version 1.7 - * @see GeometryExtracter - */ -public class LineStringExtracter - implements GeometryFilter -{ - /** - * Extracts the {@link LineString} elements from a single {@link Geometry} - * and adds them to the provided {@link List}. - * - * @param geom the geometry from which to extract - * @param lines the list to add the extracted LineStrings to - * @return the list argument - */ - public static List getLines(Geometry geom, List lines) - { - if (geom instanceof LineString) { - lines.add(geom); - } - else if (geom instanceof GeometryCollection) { - geom.apply(new LineStringExtracter(lines)); - } - // skip non-LineString elemental geometries - - return lines; - } - - /** - * Extracts the {@link LineString} elements from a single {@link Geometry} - * and returns them in a {@link List}. - * - * @param geom the geometry from which to extract - * @return a list containing the linear elements - */ - public static List getLines(Geometry geom) - { - return getLines(geom, new ArrayList()); - } - - /** - * Extracts the {@link LineString} elements from a single {@link Geometry} - * and returns them as either a {@link LineString) or {@link MultiLineString}. - * - * @param geom the geometry from which to extract - * @return a linear geometry - */ - public static Geometry getGeometry(Geometry geom) - { - return geom.getFactory().buildGeometry(getLines(geom)); - } - - private List comps; - - /** - * Constructs a filter with a list in which to store the elements found. - */ - public LineStringExtracter(List comps) - { - this.comps = comps; - } - - public void filter(Geometry geom) - { - if (geom instanceof LineString) comps.add(geom); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java deleted file mode 100644 index 9a1ea22b01..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java +++ /dev/null @@ -1,222 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; - -/** - * Extracts all the 1-dimensional ({@link LineString}) components from a {@link Geometry}. - * For polygonal geometries, this will extract all the component {@link LinearRing}s. - * If desired, LinearRings can be forced to be returned as LineStrings. - * - * @version 1.7 - */ -public class LinearComponentExtracter - implements GeometryComponentFilter -{ - /** - * Extracts the linear components from a single {@link Geometry} - * and adds them to the provided {@link Collection}. - * - * @param geoms the collection of geometries from which to extract linear components - * @param lines the collection to add the extracted linear components to - * @return the collection of linear components (LineStrings or LinearRings) - */ - public static Collection getLines(Collection geoms, Collection lines) - { - for (Iterator i = geoms.iterator(); i.hasNext(); ) { - Geometry g = (Geometry) i.next(); - getLines(g, lines); - } - return lines; - } - - /** - * Extracts the linear components from a single {@link Geometry} - * and adds them to the provided {@link Collection}. - * - * @param geoms the Collection of geometries from which to extract linear components - * @param lines the collection to add the extracted linear components to - * @param forceToLineString true if LinearRings should be converted to LineStrings - * @return the collection of linear components (LineStrings or LinearRings) - */ - public static Collection getLines(Collection geoms, Collection lines, boolean forceToLineString) - { - for (Iterator i = geoms.iterator(); i.hasNext(); ) { - Geometry g = (Geometry) i.next(); - getLines(g, lines, forceToLineString); - } - return lines; - } - - /** - * Extracts the linear components from a single {@link Geometry} - * and adds them to the provided {@link Collection}. - * - * @param geom the geometry from which to extract linear components - * @param lines the Collection to add the extracted linear components to - * @return the Collection of linear components (LineStrings or LinearRings) - */ - public static Collection getLines(Geometry geom, Collection lines) - { - if (geom instanceof LineString) { - lines.add(geom); - } - else { - geom.apply(new LinearComponentExtracter(lines)); - } - return lines; - } - - /** - * Extracts the linear components from a single {@link Geometry} - * and adds them to the provided {@link Collection}. - * - * @param geom the geometry from which to extract linear components - * @param lines the Collection to add the extracted linear components to - * @param forceToLineString true if LinearRings should be converted to LineStrings - * @return the Collection of linear components (LineStrings or LinearRings) - */ - public static Collection getLines(Geometry geom, Collection lines, boolean forceToLineString) - { - geom.apply(new LinearComponentExtracter(lines, forceToLineString)); - return lines; - } - - /** - * Extracts the linear components from a single geometry. - * If more than one geometry is to be processed, it is more - * efficient to create a single {@link LinearComponentExtracter} instance - * and pass it to multiple geometries. - * - * @param geom the geometry from which to extract linear components - * @return the list of linear components - */ - public static List getLines(Geometry geom) - { - return getLines(geom, false); - } - - /** - * Extracts the linear components from a single geometry. - * If more than one geometry is to be processed, it is more - * efficient to create a single {@link LinearComponentExtracter} instance - * and pass it to multiple geometries. - * - * @param geom the geometry from which to extract linear components - * @param forceToLineString true if LinearRings should be converted to LineStrings - * @return the list of linear components - */ - public static List getLines(Geometry geom, boolean forceToLineString) - { - List lines = new ArrayList(); - geom.apply(new LinearComponentExtracter(lines, forceToLineString)); - return lines; - } - - /** - * Extracts the linear components from a single {@link Geometry} - * and returns them as either a {@link LineString) or {@link MultiLineString}. - * - * @param geom the geometry from which to extract - * @return a linear geometry - */ - public static Geometry getGeometry(Geometry geom) - { - return geom.getFactory().buildGeometry(getLines(geom)); - } - - - /** - * Extracts the linear components from a single {@link Geometry} - * and returns them as either a {@link LineString) or {@link MultiLineString}. - * - * @param geom the geometry from which to extract - * @param forceToLineString true if LinearRings should be converted to LineStrings - * @return a linear geometry - */ - public static Geometry getGeometry(Geometry geom, boolean forceToLineString) - { - return geom.getFactory().buildGeometry(getLines(geom, forceToLineString)); - } - - - private Collection lines; - private boolean isForcedToLineString = false; - - /** - * Constructs a LineExtracterFilter with a list in which to store LineStrings found. - */ - public LinearComponentExtracter(Collection lines) - { - this.lines = lines; - } - - /** - * Constructs a LineExtracterFilter with a list in which to store LineStrings found. - */ - public LinearComponentExtracter(Collection lines, boolean isForcedToLineString) - { - this.lines = lines; - this.isForcedToLineString = isForcedToLineString; - } - - /** - * Indicates that LinearRing components should be - * converted to pure LineStrings. - * - * @param isForcedToLineString true if LinearRings should be converted to LineStrings - */ - public void setForceToLineString(boolean isForcedToLineString) - { - this.isForcedToLineString = isForcedToLineString; - } - - public void filter(Geometry geom) - { - if (isForcedToLineString && geom instanceof LinearRing) { - LineString line = geom.getFactory().createLineString( ((LinearRing) geom).getCoordinateSequence()); - lines.add(line); - return; - } - // if not being forced, and this is a linear component - if (geom instanceof LineString) - lines.add(geom); - - // else this is not a linear component, so skip it - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/NoninvertibleTransformationException.java b/src/main/java/com/vividsolutions/jts/geom/util/NoninvertibleTransformationException.java deleted file mode 100644 index 7efb031844..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/NoninvertibleTransformationException.java +++ /dev/null @@ -1,53 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -/** - * Indicates that an {@link AffineTransformation} - * is non-invertible. - * - * @author Martin Davis - */ -public class NoninvertibleTransformationException - extends Exception -{ - public NoninvertibleTransformationException() - { - super(); - } - public NoninvertibleTransformationException(String msg) - { - super(msg); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/PointExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/PointExtracter.java deleted file mode 100644 index 51dcb06562..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/PointExtracter.java +++ /dev/null @@ -1,96 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; - -/** - * Extracts all the 0-dimensional ({@link Point}) components from a {@link Geometry}. - * - * @version 1.7 - * @see GeometryExtracter - */ -public class PointExtracter - implements GeometryFilter -{ - /** - * Extracts the {@link Point} elements from a single {@link Geometry} - * and adds them to the provided {@link List}. - * - * @param geom the geometry from which to extract - * @param list the list to add the extracted elements to - */ - public static List getPoints(Geometry geom, List list) - { - if (geom instanceof Point) { - list.add(geom); - } - else if (geom instanceof GeometryCollection) { - geom.apply(new PointExtracter(list)); - } - // skip non-Polygonal elemental geometries - - return list; - } - - /** - * Extracts the {@link Point} elements from a single {@link Geometry} - * and returns them in a {@link List}. - * - * @param geom the geometry from which to extract - */ - public static List getPoints(Geometry geom) { - if (geom instanceof Point) { - return Collections.singletonList(geom); - } - return getPoints(geom, new ArrayList()); - } - - private List pts; - /** - * Constructs a PointExtracterFilter with a list in which to store Points found. - */ - public PointExtracter(List pts) - { - this.pts = pts; - } - - public void filter(Geometry geom) - { - if (geom instanceof Point) pts.add(geom); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/PolygonExtracter.java b/src/main/java/com/vividsolutions/jts/geom/util/PolygonExtracter.java deleted file mode 100644 index 98c1dbbfd2..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/PolygonExtracter.java +++ /dev/null @@ -1,93 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geom.util; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Extracts all the {@link Polygon} elements from a {@link Geometry}. - * - * @version 1.7 - * @see GeometryExtracter - */ -public class PolygonExtracter - implements GeometryFilter -{ - /** - * Extracts the {@link Polygon} elements from a single {@link Geometry} - * and adds them to the provided {@link List}. - * - * @param geom the geometry from which to extract - * @param list the list to add the extracted elements to - */ - public static List getPolygons(Geometry geom, List list) - { - if (geom instanceof Polygon) { - list.add(geom); - } - else if (geom instanceof GeometryCollection) { - geom.apply(new PolygonExtracter(list)); - } - // skip non-Polygonal elemental geometries - - return list; - } - - /** - * Extracts the {@link Polygon} elements from a single {@link Geometry} - * and returns them in a {@link List}. - * - * @param geom the geometry from which to extract - */ - public static List getPolygons(Geometry geom) - { - return getPolygons(geom, new ArrayList()); - } - - private List comps; - /** - * Constructs a PolygonExtracterFilter with a list in which to store Polygons found. - */ - public PolygonExtracter(List comps) - { - this.comps = comps; - } - - public void filter(Geometry geom) - { - if (geom instanceof Polygon) comps.add(geom); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java b/src/main/java/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java deleted file mode 100644 index 0d4856e2e6..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java +++ /dev/null @@ -1,69 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.geom.*; - -/** - * A visitor to {@link Geometry} componets, which - * allows short-circuiting when a defined condition holds. - * - * @version 1.7 - */ -public abstract class ShortCircuitedGeometryVisitor -{ - private boolean isDone = false; - - public ShortCircuitedGeometryVisitor() { - } - - public void applyTo(Geometry geom) { - for (int i = 0; i < geom.getNumGeometries() && ! isDone; i++) { - Geometry element = geom.getGeometryN(i); - if (! (element instanceof GeometryCollection)) { - visit(element); - if (isDone()) { - isDone = true; - return; - } - } - else - applyTo(element); - } - } - - protected abstract void visit(Geometry element); - - protected abstract boolean isDone(); -} diff --git a/src/main/java/com/vividsolutions/jts/geom/util/SineStarFactory.java b/src/main/java/com/vividsolutions/jts/geom/util/SineStarFactory.java deleted file mode 100644 index cd251a4457..0000000000 --- a/src/main/java/com/vividsolutions/jts/geom/util/SineStarFactory.java +++ /dev/null @@ -1,148 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.geom.util; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * Creates geometries which are shaped like multi-armed stars - * with each arm shaped like a sine wave. - * These kinds of geometries are useful as a more complex - * geometry for testing algorithms. - * - * @author Martin Davis - * - */ -public class SineStarFactory - extends GeometricShapeFactory -{ - protected int numArms = 8; - protected double armLengthRatio = 0.5; - - /** - * Creates a factory which will create sine stars using the default - * {@link GeometryFactory}. - * - * @param geomFact the factory to use - */ - public SineStarFactory() - { - super(); - } - - /** - * Creates a factory which will create sine stars using the given - * {@link GeometryFactory}. - * - * @param geomFact the factory to use - */ - public SineStarFactory(GeometryFactory geomFact) - { - super(geomFact); - } - - /** - * Sets the number of arms in the star - * - * @param numArms the number of arms to generate - */ - public void setNumArms(int numArms) - { - this.numArms = numArms; - } - - /** - * Sets the ration of the length of each arm to the distance from the tip - * of the arm to the centre of the star. - * Value should be between 0.0 and 1.0 - * - * @param armLengthRatio - */ - public void setArmLengthRatio(double armLengthRatio) - { - this.armLengthRatio = armLengthRatio; - } - - /** - * Generates the geometry for the sine star - * - * @return the geometry representing the sine star - */ - public Geometry createSineStar() - { - Envelope env = dim.getEnvelope(); - double radius = env.getWidth() / 2.0; - - double armRatio = armLengthRatio; - if (armRatio < 0.0) - armRatio = 0.0; - if (armRatio > 1.0) - armRatio = 1.0; - - double armMaxLen = armRatio * radius; - double insideRadius = (1 - armRatio) * radius; - - double centreX = env.getMinX() + radius; - double centreY = env.getMinY() + radius; - - Coordinate[] pts = new Coordinate[nPts + 1]; - int iPt = 0; - for (int i = 0; i < nPts; i++) { - // the fraction of the way thru the current arm - in [0,1] - double ptArcFrac = (i / (double) nPts) * numArms; - double armAngFrac = ptArcFrac - Math.floor(ptArcFrac); - - // the angle for the current arm - in [0,2Pi] - // (each arm is a complete sine wave cycle) - double armAng = 2 * Math.PI * armAngFrac; - // the current length of the arm - double armLenFrac = (Math.cos(armAng) + 1.0) / 2.0; - - // the current radius of the curve (core + arm) - double curveRadius = insideRadius + armMaxLen * armLenFrac; - - // the current angle of the curve - double ang = i * (2 * Math.PI / nPts); - double x = curveRadius * Math.cos(ang) + centreX; - double y = curveRadius * Math.sin(ang) + centreY; - pts[iPt++] = coord(x, y); - } - pts[iPt] = new Coordinate(pts[0]); - - LinearRing ring = geomFact.createLinearRing(pts); - Polygon poly = geomFact.createPolygon(ring, null); - return poly; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Depth.java b/src/main/java/com/vividsolutions/jts/geomgraph/Depth.java deleted file mode 100644 index 3293f3723e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Depth.java +++ /dev/null @@ -1,159 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import com.vividsolutions.jts.geomgraph.Position; -import com.vividsolutions.jts.geom.Location; - -/** - * A Depth object records the topological depth of the sides - * of an Edge for up to two Geometries. - * @version 1.7 - */ -public class Depth { - - private final static int NULL_VALUE = -1; - - public static int depthAtLocation(int location) - { - if (location == Location.EXTERIOR) return 0; - if (location == Location.INTERIOR) return 1; - return NULL_VALUE; - } - - private int[][] depth = new int[2][3]; - - public Depth() { - // initialize depth array to a sentinel value - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 3; j++) { - depth[i][j] = NULL_VALUE; - } - } - } - - public int getDepth(int geomIndex, int posIndex) - { - return depth[geomIndex][posIndex]; - } - public void setDepth(int geomIndex, int posIndex, int depthValue) - { - depth[geomIndex][posIndex] = depthValue; - } - public int getLocation(int geomIndex, int posIndex) - { - if (depth[geomIndex][posIndex] <= 0) return Location.EXTERIOR; - return Location.INTERIOR; - } - public void add(int geomIndex, int posIndex, int location) - { - if (location == Location.INTERIOR) - depth[geomIndex][posIndex]++; - } - /** - * A Depth object is null (has never been initialized) if all depths are null. - */ - public boolean isNull() - { - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 3; j++) { - if (depth[i][j] != NULL_VALUE) - return false; - } - } - return true; - } - public boolean isNull(int geomIndex) - { - return depth[geomIndex][1] == NULL_VALUE; - } - public boolean isNull(int geomIndex, int posIndex) - { - return depth[geomIndex][posIndex] == NULL_VALUE; - } - public void add(Label lbl) - { - for (int i = 0; i < 2; i++) { - for (int j = 1; j < 3; j++) { - int loc = lbl.getLocation(i, j); - if (loc == Location.EXTERIOR || loc == Location.INTERIOR) { - // initialize depth if it is null, otherwise add this location value - if (isNull(i, j)) { - depth[i][j] = depthAtLocation(loc); - } - else - depth[i][j] += depthAtLocation(loc); - } - } - } - } - public int getDelta(int geomIndex) - { - return depth[geomIndex][Position.RIGHT] - depth[geomIndex][Position.LEFT]; - } - /** - * Normalize the depths for each geometry, if they are non-null. - * A normalized depth - * has depth values in the set { 0, 1 }. - * Normalizing the depths - * involves reducing the depths by the same amount so that at least - * one of them is 0. If the remaining value is > 0, it is set to 1. - */ - public void normalize() - { - for (int i = 0; i < 2; i++) { - if (! isNull(i)) { - int minDepth = depth[i][1]; - if (depth[i][2] < minDepth) - minDepth = depth[i][2]; - - if (minDepth < 0) minDepth = 0; - for (int j = 1; j < 3; j++) { - int newValue = 0; - if (depth[i][j] > minDepth) - newValue = 1; - depth[i][j] = newValue; - } - } - } - } - - public String toString() - { - return - "A: " + depth[0][1] + "," + depth[0][2] - + " B: " + depth[1][1] + "," + depth[1][2]; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdge.java b/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdge.java deleted file mode 100644 index 0fdc7786ed..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdge.java +++ /dev/null @@ -1,239 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geom.*; - - -/** - * @version 1.7 - */ -public class DirectedEdge - extends EdgeEnd -{ - - /** - * Computes the factor for the change in depth when moving from one location to another. - * E.g. if crossing from the INTERIOR to the EXTERIOR the depth decreases, so the factor is -1 - */ - public static int depthFactor(int currLocation, int nextLocation) - { - if (currLocation == Location.EXTERIOR && nextLocation == Location.INTERIOR) - return 1; - else if (currLocation == Location.INTERIOR && nextLocation == Location.EXTERIOR) - return -1; - return 0; - } - - protected boolean isForward; - private boolean isInResult = false; - private boolean isVisited = false; - - private DirectedEdge sym; // the symmetric edge - private DirectedEdge next; // the next edge in the edge ring for the polygon containing this edge - private DirectedEdge nextMin; // the next edge in the MinimalEdgeRing that contains this edge - private EdgeRing edgeRing; // the EdgeRing that this edge is part of - private EdgeRing minEdgeRing; // the MinimalEdgeRing that this edge is part of - /** - * The depth of each side (position) of this edge. - * The 0 element of the array is never used. - */ - private int[] depth = { 0, -999, -999 }; - - public DirectedEdge(Edge edge, boolean isForward) - { - super(edge); - this.isForward = isForward; - if (isForward) { - init(edge.getCoordinate(0), edge.getCoordinate(1)); - } - else { - int n = edge.getNumPoints() - 1; - init(edge.getCoordinate(n), edge.getCoordinate(n-1)); - } - computeDirectedLabel(); - } - public Edge getEdge() { return edge; } - public void setInResult(boolean isInResult) { this.isInResult = isInResult; } - public boolean isInResult() { return isInResult; } - public boolean isVisited() { return isVisited; } - public void setVisited(boolean isVisited) { this.isVisited = isVisited; } - public void setEdgeRing(EdgeRing edgeRing) { this.edgeRing = edgeRing; } - public EdgeRing getEdgeRing() { return edgeRing; } - public void setMinEdgeRing(EdgeRing minEdgeRing) { this.minEdgeRing = minEdgeRing; } - public EdgeRing getMinEdgeRing() { return minEdgeRing; } - public int getDepth(int position) { return depth[position]; } - - public void setDepth(int position, int depthVal) - { - if (depth[position] != -999) { -// if (depth[position] != depthVal) { -// Debug.print(this); -// } - if (depth[position] != depthVal) - throw new TopologyException("assigned depths do not match", getCoordinate()); - //Assert.isTrue(depth[position] == depthVal, "assigned depths do not match at " + getCoordinate()); - } - depth[position] = depthVal; - } - - public int getDepthDelta() - { - int depthDelta = edge.getDepthDelta(); - if (! isForward) depthDelta = -depthDelta; - return depthDelta; - } - - /** - * setVisitedEdge marks both DirectedEdges attached to a given Edge. - * This is used for edges corresponding to lines, which will only - * appear oriented in a single direction in the result. - */ - public void setVisitedEdge(boolean isVisited) - { - setVisited(isVisited); - sym.setVisited(isVisited); - } - /** - * Each Edge gives rise to a pair of symmetric DirectedEdges, in opposite - * directions. - * @return the DirectedEdge for the same Edge but in the opposite direction - */ - public DirectedEdge getSym() { return sym; } - public boolean isForward() { return isForward; } - public void setSym(DirectedEdge de) - { - sym = de; - } - public DirectedEdge getNext() { return next; } - public void setNext(DirectedEdge next) { this.next = next; } - public DirectedEdge getNextMin() { return nextMin; } - public void setNextMin(DirectedEdge nextMin) { this.nextMin = nextMin; } - - /** - * This edge is a line edge if - *

                      - *
                    • at least one of the labels is a line label - *
                    • any labels which are not line labels have all Locations = EXTERIOR - *
                    - */ - public boolean isLineEdge() - { - boolean isLine = label.isLine(0) || label.isLine(1); - boolean isExteriorIfArea0 = - ! label.isArea(0) || label.allPositionsEqual(0, Location.EXTERIOR); - boolean isExteriorIfArea1 = - ! label.isArea(1) || label.allPositionsEqual(1, Location.EXTERIOR); - - return isLine && isExteriorIfArea0 && isExteriorIfArea1; - } - /** - * This is an interior Area edge if - *
                      - *
                    • its label is an Area label for both Geometries - *
                    • and for each Geometry both sides are in the interior. - *
                    - * - * @return true if this is an interior Area edge - */ - public boolean isInteriorAreaEdge() - { - boolean isInteriorAreaEdge = true; - for (int i = 0; i < 2; i++) { - if (! ( label.isArea(i) - && label.getLocation(i, Position.LEFT ) == Location.INTERIOR - && label.getLocation(i, Position.RIGHT) == Location.INTERIOR) ) { - isInteriorAreaEdge = false; - } - } - return isInteriorAreaEdge; - } - - /** - * Compute the label in the appropriate orientation for this DirEdge - */ - private void computeDirectedLabel() - { - label = new Label(edge.getLabel()); - if (! isForward) - label.flip(); - } - - /** - * Set both edge depths. One depth for a given side is provided. The other is - * computed depending on the Location transition and the depthDelta of the edge. - */ - public void setEdgeDepths(int position, int depth) - { - // get the depth transition delta from R to L for this directed Edge - int depthDelta = getEdge().getDepthDelta(); - if (! isForward) depthDelta = -depthDelta; - - // if moving from L to R instead of R to L must change sign of delta - int directionFactor = 1; - if (position == Position.LEFT) - directionFactor = -1; - - int oppositePos = Position.opposite(position); - int delta = depthDelta * directionFactor; - //TESTINGint delta = depthDelta * DirectedEdge.depthFactor(loc, oppositeLoc); - int oppositeDepth = depth + delta; - setDepth(position, depth); - setDepth(oppositePos, oppositeDepth); - } - - public void print(PrintStream out) - { - super.print(out); - out.print(" " + depth[Position.LEFT] + "/" + depth[Position.RIGHT]); - out.print(" (" + getDepthDelta() + ")"); - //out.print(" " + this.hashCode()); - //if (next != null) out.print(" next:" + next.hashCode()); - if (isInResult) out.print(" inResult"); - } - public void printEdge(PrintStream out) - { - print(out); - out.print(" "); - if (isForward) - edge.print(out); - else - edge.printReverse(out); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java b/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java deleted file mode 100644 index dc0cde4611..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java +++ /dev/null @@ -1,406 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * A DirectedEdgeStar is an ordered list of outgoing DirectedEdges around a node. - * It supports labelling the edges as well as linking the edges to form both - * MaximalEdgeRings and MinimalEdgeRings. - * - * @version 1.7 - */ -public class DirectedEdgeStar - extends EdgeEndStar -{ - - /** - * A list of all outgoing edges in the result, in CCW order - */ - private List resultAreaEdgeList; - private Label label; - - public DirectedEdgeStar() { - } - /** - * Insert a directed edge in the list - */ - public void insert(EdgeEnd ee) - { - DirectedEdge de = (DirectedEdge) ee; - insertEdgeEnd(de, de); - } - - public Label getLabel() { return label; } - - public int getOutgoingDegree() - { - int degree = 0; - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.isInResult()) degree++; - } - return degree; - } - public int getOutgoingDegree(EdgeRing er) - { - int degree = 0; - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.getEdgeRing() == er) degree++; - } - return degree; - } - - public DirectedEdge getRightmostEdge() - { - List edges = getEdges(); - int size = edges.size(); - if (size < 1) return null; - DirectedEdge de0 = (DirectedEdge) edges.get(0); - if (size == 1) return de0; - DirectedEdge deLast = (DirectedEdge) edges.get(size - 1); - - int quad0 = de0.getQuadrant(); - int quad1 = deLast.getQuadrant(); - if (Quadrant.isNorthern(quad0) && Quadrant.isNorthern(quad1)) - return de0; - else if (! Quadrant.isNorthern(quad0) && ! Quadrant.isNorthern(quad1)) - return deLast; - else { - // edges are in different hemispheres - make sure we return one that is non-horizontal - //Assert.isTrue(de0.getDy() != 0, "should never return horizontal edge!"); - DirectedEdge nonHorizontalEdge = null; - if (de0.getDy() != 0) - return de0; - else if (deLast.getDy() != 0) - return deLast; - } - Assert.shouldNeverReachHere("found two horizontal edges incident on node"); - return null; - - } - /** - * Compute the labelling for all dirEdges in this star, as well - * as the overall labelling - */ - public void computeLabelling(GeometryGraph[] geom) - { -//Debug.print(this); - super.computeLabelling(geom); - - // determine the overall labelling for this DirectedEdgeStar - // (i.e. for the node it is based at) - label = new Label(Location.NONE); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd ee = (EdgeEnd) it.next(); - Edge e = ee.getEdge(); - Label eLabel = e.getLabel(); - for (int i = 0; i < 2; i++) { - int eLoc = eLabel.getLocation(i); - if (eLoc == Location.INTERIOR || eLoc == Location.BOUNDARY) - label.setLocation(i, Location.INTERIOR); - } - } -//Debug.print(this); - } - - /** - * For each dirEdge in the star, - * merge the label from the sym dirEdge into the label - */ - public void mergeSymLabels() - { - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - Label label = de.getLabel(); - label.merge(de.getSym().getLabel()); - } - } - - /** - * Update incomplete dirEdge labels from the labelling for the node - */ - public void updateLabelling(Label nodeLabel) - { - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - Label label = de.getLabel(); - label.setAllLocationsIfNull(0, nodeLabel.getLocation(0)); - label.setAllLocationsIfNull(1, nodeLabel.getLocation(1)); - } - } - - private List getResultAreaEdges() - { -//print(System.out); - if (resultAreaEdgeList != null) return resultAreaEdgeList; - resultAreaEdgeList = new ArrayList(); - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.isInResult() || de.getSym().isInResult() ) - resultAreaEdgeList.add(de); - } - return resultAreaEdgeList; - } - - private final int SCANNING_FOR_INCOMING = 1; - private final int LINKING_TO_OUTGOING = 2; - /** - * Traverse the star of DirectedEdges, linking the included edges together. - * To link two dirEdges, the pointer for an incoming dirEdge - * is set to the next outgoing edge. - *

                    - * DirEdges are only linked if: - *

                      - *
                    • they belong to an area (i.e. they have sides) - *
                    • they are marked as being in the result - *
                    - *

                    - * Edges are linked in CCW order (the order they are stored). - * This means that rings have their face on the Right - * (in other words, - * the topological location of the face is given by the RHS label of the DirectedEdge) - *

                    - * PRECONDITION: No pair of dirEdges are both marked as being in the result - */ - public void linkResultDirectedEdges() - { - // make sure edges are copied to resultAreaEdges list - getResultAreaEdges(); - // find first area edge (if any) to start linking at - DirectedEdge firstOut = null; - DirectedEdge incoming = null; - int state = SCANNING_FOR_INCOMING; - // link edges in CCW order - for (int i = 0; i < resultAreaEdgeList.size(); i++) { - DirectedEdge nextOut = (DirectedEdge) resultAreaEdgeList.get(i); - DirectedEdge nextIn = nextOut.getSym(); - - // skip de's that we're not interested in - if (! nextOut.getLabel().isArea()) continue; - - // record first outgoing edge, in order to link the last incoming edge - if (firstOut == null && nextOut.isInResult()) firstOut = nextOut; - // assert: sym.isInResult() == false, since pairs of dirEdges should have been removed already - - switch (state) { - case SCANNING_FOR_INCOMING: - if (! nextIn.isInResult()) continue; - incoming = nextIn; - state = LINKING_TO_OUTGOING; - break; - case LINKING_TO_OUTGOING: - if (! nextOut.isInResult()) continue; - incoming.setNext(nextOut); - state = SCANNING_FOR_INCOMING; - break; - } - } -//Debug.print(this); - if (state == LINKING_TO_OUTGOING) { -//Debug.print(firstOut == null, this); - if (firstOut == null) - throw new TopologyException("no outgoing dirEdge found", getCoordinate()); - //Assert.isTrue(firstOut != null, "no outgoing dirEdge found (at " + getCoordinate() ); - Assert.isTrue(firstOut.isInResult(), "unable to link last incoming dirEdge"); - incoming.setNext(firstOut); - } - } - public void linkMinimalDirectedEdges(EdgeRing er) - { - // find first area edge (if any) to start linking at - DirectedEdge firstOut = null; - DirectedEdge incoming = null; - int state = SCANNING_FOR_INCOMING; - // link edges in CW order - for (int i = resultAreaEdgeList.size() - 1; i >= 0; i--) { - DirectedEdge nextOut = (DirectedEdge) resultAreaEdgeList.get(i); - DirectedEdge nextIn = nextOut.getSym(); - - // record first outgoing edge, in order to link the last incoming edge - if (firstOut == null && nextOut.getEdgeRing() == er) firstOut = nextOut; - - switch (state) { - case SCANNING_FOR_INCOMING: - if (nextIn.getEdgeRing() != er) continue; - incoming = nextIn; - state = LINKING_TO_OUTGOING; - break; - case LINKING_TO_OUTGOING: - if (nextOut.getEdgeRing() != er) continue; - incoming.setNextMin(nextOut); - state = SCANNING_FOR_INCOMING; - break; - } - } -//print(System.out); - if (state == LINKING_TO_OUTGOING) { - Assert.isTrue(firstOut != null, "found null for first outgoing dirEdge"); - Assert.isTrue(firstOut.getEdgeRing() == er, "unable to link last incoming dirEdge"); - incoming.setNextMin(firstOut); - } - } - public void linkAllDirectedEdges() - { - getEdges(); - // find first area edge (if any) to start linking at - DirectedEdge prevOut = null; - DirectedEdge firstIn = null; - // link edges in CW order - for (int i = edgeList.size() - 1; i >= 0; i--) { - DirectedEdge nextOut = (DirectedEdge) edgeList.get(i); - DirectedEdge nextIn = nextOut.getSym(); - if (firstIn == null) firstIn = nextIn; - if (prevOut != null) nextIn.setNext(prevOut); - // record outgoing edge, in order to link the last incoming edge - prevOut = nextOut; - } - firstIn.setNext(prevOut); -//Debug.print(this); - } - - /** - * Traverse the star of edges, maintaing the current location in the result - * area at this node (if any). - * If any L edges are found in the interior of the result, mark them as covered. - */ - public void findCoveredLineEdges() - { -//Debug.print("findCoveredLineEdges"); -//Debug.print(this); - // Since edges are stored in CCW order around the node, - // as we move around the ring we move from the right to the left side of the edge - - /** - * Find first DirectedEdge of result area (if any). - * The interior of the result is on the RHS of the edge, - * so the start location will be: - * - INTERIOR if the edge is outgoing - * - EXTERIOR if the edge is incoming - */ - int startLoc = Location.NONE ; - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge nextOut = (DirectedEdge) it.next(); - DirectedEdge nextIn = nextOut.getSym(); - if (! nextOut.isLineEdge()) { - if (nextOut.isInResult()) { - startLoc = Location.INTERIOR; - break; - } - if (nextIn.isInResult()) { - startLoc = Location.EXTERIOR; - break; - } - } - } - // no A edges found, so can't determine if L edges are covered or not - if (startLoc == Location.NONE) return; - - /** - * move around ring, keeping track of the current location - * (Interior or Exterior) for the result area. - * If L edges are found, mark them as covered if they are in the interior - */ - int currLoc = startLoc; - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge nextOut = (DirectedEdge) it.next(); - DirectedEdge nextIn = nextOut.getSym(); - if (nextOut.isLineEdge()) { - nextOut.getEdge().setCovered(currLoc == Location.INTERIOR); -//Debug.println(nextOut); - } - else { // edge is an Area edge - if (nextOut.isInResult()) - currLoc = Location.EXTERIOR; - if (nextIn.isInResult()) - currLoc = Location.INTERIOR; - } - } - } - - public void computeDepths(DirectedEdge de) - { - int edgeIndex = findIndex(de); - Label label = de.getLabel(); - int startDepth = de.getDepth(Position.LEFT); - int targetLastDepth = de.getDepth(Position.RIGHT); - // compute the depths from this edge up to the end of the edge array - int nextDepth = computeDepths(edgeIndex + 1, edgeList.size(), startDepth); - // compute the depths for the initial part of the array - int lastDepth = computeDepths(0, edgeIndex, nextDepth); -//Debug.print(lastDepth != targetLastDepth, this); -//Debug.print(lastDepth != targetLastDepth, "mismatch: " + lastDepth + " / " + targetLastDepth); - if (lastDepth != targetLastDepth) - throw new TopologyException("depth mismatch at " + de.getCoordinate()); - //Assert.isTrue(lastDepth == targetLastDepth, "depth mismatch at " + de.getCoordinate()); - } - - /** - * Compute the DirectedEdge depths for a subsequence of the edge array. - * - * @return the last depth assigned (from the R side of the last edge visited) - */ - private int computeDepths(int startIndex, int endIndex, int startDepth) - { - int currDepth = startDepth; - for (int i = startIndex; i < endIndex ; i++) { - DirectedEdge nextDe = (DirectedEdge) edgeList.get(i); - Label label = nextDe.getLabel(); - nextDe.setEdgeDepths(Position.RIGHT, currDepth); - currDepth = nextDe.getDepth(Position.LEFT); - } - return currDepth; - } - - public void print(PrintStream out) - { - System.out.println("DirectedEdgeStar: " + getCoordinate()); - for (Iterator it = iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - out.print("out "); - de.print(out); - out.println(); - out.print("in "); - de.getSym().print(out); - out.println(); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Edge.java b/src/main/java/com/vividsolutions/jts/geomgraph/Edge.java deleted file mode 100644 index 5736519e7e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Edge.java +++ /dev/null @@ -1,291 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import java.util.Iterator; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geomgraph.index.*; - - -/** - * @version 1.7 - */ -public class Edge - extends GraphComponent -{ - - /** - * Updates an IM from the label for an edge. - * Handles edges from both L and A geometries. - */ - public static void updateIM(Label label, IntersectionMatrix im) - { - im.setAtLeastIfValid(label.getLocation(0, Position.ON), label.getLocation(1, Position.ON), 1); - if (label.isArea()) { - im.setAtLeastIfValid(label.getLocation(0, Position.LEFT), label.getLocation(1, Position.LEFT), 2); - im.setAtLeastIfValid(label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), 2); - } - } - - Coordinate[] pts; - private Envelope env; - EdgeIntersectionList eiList = new EdgeIntersectionList(this); - private String name; - private MonotoneChainEdge mce; - private boolean isIsolated = true; - private Depth depth = new Depth(); - private int depthDelta = 0; // the change in area depth from the R to L side of this edge - - public Edge(Coordinate[] pts, Label label) - { - this.pts = pts; - this.label = label; - } - public Edge(Coordinate[] pts) - { - this(pts, null); - } - - public int getNumPoints() { return pts.length; } - public void setName(String name) { this.name = name; } - public Coordinate[] getCoordinates() { return pts; } - public Coordinate getCoordinate(int i) - { - return pts[i]; - } - public Coordinate getCoordinate() - { - if (pts.length > 0) return pts[0]; - return null; - } - public Envelope getEnvelope() - { - // compute envelope lazily - if (env == null) { - env = new Envelope(); - for (int i = 0; i < pts.length; i++) { - env.expandToInclude(pts[i]); - } - } - return env; - } - - public Depth getDepth() { return depth; } - - /** - * The depthDelta is the change in depth as an edge is crossed from R to L - * @return the change in depth as the edge is crossed from R to L - */ - public int getDepthDelta() { return depthDelta; } - public void setDepthDelta(int depthDelta) { this.depthDelta = depthDelta; } - - public int getMaximumSegmentIndex() - { - return pts.length - 1; - } - public EdgeIntersectionList getEdgeIntersectionList() { return eiList; } - - public MonotoneChainEdge getMonotoneChainEdge() - { - if (mce == null) mce = new MonotoneChainEdge(this); - return mce; - } - - public boolean isClosed() - { - return pts[0].equals(pts[pts.length - 1]); - } - /** - * An Edge is collapsed if it is an Area edge and it consists of - * two segments which are equal and opposite (eg a zero-width V). - */ - public boolean isCollapsed() - { - if (! label.isArea()) return false; - if (pts.length != 3) return false; - if (pts[0].equals(pts[2]) ) return true; - return false; - } - public Edge getCollapsedEdge() - { - Coordinate newPts[] = new Coordinate[2]; - newPts[0] = pts[0]; - newPts[1] = pts[1]; - Edge newe = new Edge(newPts, Label.toLineLabel(label)); - return newe; - } - - public void setIsolated(boolean isIsolated) - { - this.isIsolated = isIsolated; - } - public boolean isIsolated() - { - return isIsolated; - } - - /** - * Adds EdgeIntersections for one or both - * intersections found for a segment of an edge to the edge intersection list. - */ - public void addIntersections(LineIntersector li, int segmentIndex, int geomIndex) - { - for (int i = 0; i < li.getIntersectionNum(); i++) { - addIntersection(li, segmentIndex, geomIndex, i); - } - } - /** - * Add an EdgeIntersection for intersection intIndex. - * An intersection that falls exactly on a vertex of the edge is normalized - * to use the higher of the two possible segmentIndexes - */ - public void addIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex) - { - Coordinate intPt = new Coordinate(li.getIntersection(intIndex)); - int normalizedSegmentIndex = segmentIndex; - double dist = li.getEdgeDistance(geomIndex, intIndex); -//Debug.println("edge intpt: " + intPt + " dist: " + dist); - // normalize the intersection point location - int nextSegIndex = normalizedSegmentIndex + 1; - if (nextSegIndex < pts.length) { - Coordinate nextPt = pts[nextSegIndex]; -//Debug.println("next pt: " + nextPt); - - // Normalize segment index if intPt falls on vertex - // The check for point equality is 2D only - Z values are ignored - if (intPt.equals2D(nextPt)) { -//Debug.println("normalized distance"); - normalizedSegmentIndex = nextSegIndex; - dist = 0.0; - } - } - /** - * Add the intersection point to edge intersection list. - */ - EdgeIntersection ei = eiList.add(intPt, normalizedSegmentIndex, dist); -//ei.print(System.out); - - } - - /** - * Update the IM with the contribution for this component. - * A component only contributes if it has a labelling for both parent geometries - */ - public void computeIM(IntersectionMatrix im) - { - updateIM(label, im); - } - - /** - * equals is defined to be: - *

                    - * e1 equals e2 - * iff - * the coordinates of e1 are the same or the reverse of the coordinates in e2 - */ - public boolean equals(Object o) - { - if (! (o instanceof Edge)) return false; - Edge e = (Edge) o; - - if (pts.length != e.pts.length) return false; - - boolean isEqualForward = true; - boolean isEqualReverse = true; - int iRev = pts.length; - for (int i = 0; i < pts.length; i++) { - if (! pts[i].equals2D(e.pts[i])) { - isEqualForward = false; - } - if (! pts[i].equals2D(e.pts[--iRev])) { - isEqualReverse = false; - } - if (! isEqualForward && ! isEqualReverse) return false; - } - return true; - } - - /** - * @return true if the coordinate sequences of the Edges are identical - */ - public boolean isPointwiseEqual(Edge e) - { - if (pts.length != e.pts.length) return false; - - for (int i = 0; i < pts.length; i++) { - if (! pts[i].equals2D(e.pts[i])) { - return false; - } - } - return true; - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("edge " + name + ": "); - buf.append("LINESTRING ("); - for (int i = 0; i < pts.length; i++) { - if (i > 0) buf.append(","); - buf.append(pts[i].x + " " + pts[i].y); - } - buf.append(") " + label + " " + depthDelta); - return buf.toString(); - } - public void print(PrintStream out) - { - out.print("edge " + name + ": "); - out.print("LINESTRING ("); - for (int i = 0; i < pts.length; i++) { - if (i > 0) out.print(","); - out.print(pts[i].x + " " + pts[i].y); - } - out.print(") " + label + " " + depthDelta); - } - public void printReverse(PrintStream out) - { - out.print("edge " + name + ": "); - for (int i = pts.length - 1; i >= 0; i--) { - out.print(pts[i] + " "); - } - out.println(""); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEnd.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEnd.java deleted file mode 100644 index 4d30372818..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEnd.java +++ /dev/null @@ -1,150 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.Label; -import com.vividsolutions.jts.geomgraph.Edge; - -/** - * Models the end of an edge incident on a node. - * EdgeEnds have a direction - * determined by the direction of the ray from the initial - * point to the next point. - * EdgeEnds are comparable under the ordering - * "a has a greater angle with the x-axis than b". - * This ordering is used to sort EdgeEnds around a node. - * @version 1.7 - */ -public class EdgeEnd - implements Comparable -{ - protected Edge edge; // the parent edge of this edge end - protected Label label; - - private Node node; // the node this edge end originates at - private Coordinate p0, p1; // points of initial line segment - private double dx, dy; // the direction vector for this edge from its starting point - private int quadrant; - - protected EdgeEnd(Edge edge) - { - this.edge = edge; - } - public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1) { - this(edge, p0, p1, null); - } - public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1, Label label) { - this(edge); - init(p0, p1); - this.label = label; - } - - protected void init(Coordinate p0, Coordinate p1) - { - this.p0 = p0; - this.p1 = p1; - dx = p1.x - p0.x; - dy = p1.y - p0.y; - quadrant = Quadrant.quadrant(dx, dy); - Assert.isTrue(! (dx == 0 && dy == 0), "EdgeEnd with identical endpoints found"); - } - - public Edge getEdge() { return edge; } - public Label getLabel() { return label; } - public Coordinate getCoordinate() { return p0; } - public Coordinate getDirectedCoordinate() { return p1; } - public int getQuadrant() { return quadrant; } - public double getDx() { return dx; } - public double getDy() { return dy; } - - public void setNode(Node node) { this.node = node; } - public Node getNode() { return node; } - - public int compareTo(Object obj) - { - EdgeEnd e = (EdgeEnd) obj; - return compareDirection(e); - } - /** - * Implements the total order relation: - *

                    - * a has a greater angle with the positive x-axis than b - *

                    - * Using the obvious algorithm of simply computing the angle is not robust, - * since the angle calculation is obviously susceptible to roundoff. - * A robust algorithm is: - * - first compare the quadrant. If the quadrants - * are different, it it trivial to determine which vector is "greater". - * - if the vectors lie in the same quadrant, the computeOrientation function - * can be used to decide the relative orientation of the vectors. - */ - public int compareDirection(EdgeEnd e) - { - if (dx == e.dx && dy == e.dy) - return 0; - // if the rays are in different quadrants, determining the ordering is trivial - if (quadrant > e.quadrant) return 1; - if (quadrant < e.quadrant) return -1; - // vectors are in the same quadrant - check relative orientation of direction vectors - // this is > e if it is CCW of e - return CGAlgorithms.computeOrientation(e.p0, e.p1, p1); - } - - public void computeLabel(BoundaryNodeRule boundaryNodeRule) - { - // subclasses should override this if they are using labels - } - public void print(PrintStream out) - { - double angle = Math.atan2(dy, dx); - String className = getClass().getName(); - int lastDotPos = className.lastIndexOf('.'); - String name = className.substring(lastDotPos + 1); - out.print(" " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle + " " + label); - } - public String toString() - { - double angle = Math.atan2(dy, dx); - String className = getClass().getName(); - int lastDotPos = className.lastIndexOf('.'); - String name = className.substring(lastDotPos + 1); - return " " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle + " " + label; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEndStar.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEndStar.java deleted file mode 100644 index 73fee52b7e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeEndStar.java +++ /dev/null @@ -1,352 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.algorithm.locate.SimplePointInAreaLocator; -import com.vividsolutions.jts.util.*; - -/** - * A EdgeEndStar is an ordered list of EdgeEnds around a node. - * They are maintained in CCW order (starting with the positive x-axis) around the node - * for efficient lookup and topology building. - * - * @version 1.7 - */ -abstract public class EdgeEndStar -{ - - /** - * A map which maintains the edges in sorted order around the node - */ - protected Map edgeMap = new TreeMap(); - /** - * A list of all outgoing edges in the result, in CCW order - */ - protected List edgeList; - /** - * The location of the point for this star in Geometry i Areas - */ - private int[] ptInAreaLocation = { Location.NONE, Location.NONE }; - - public EdgeEndStar() - { - - } - - /** - * Insert a EdgeEnd into this EdgeEndStar - */ - abstract public void insert(EdgeEnd e); - - /** - * Insert an EdgeEnd into the map, and clear the edgeList cache, - * since the list of edges has now changed - */ - protected void insertEdgeEnd(EdgeEnd e, Object obj) - { - edgeMap.put(e, obj); - edgeList = null; // edge list has changed - clear the cache - } - - /** - * @return the coordinate for the node this star is based at - */ - public Coordinate getCoordinate() - { - Iterator it = iterator(); - if (! it.hasNext()) return null; - EdgeEnd e = (EdgeEnd) it.next(); - return e.getCoordinate(); - } - public int getDegree() - { - return edgeMap.size(); - } - - /** - * Iterator access to the ordered list of edges is optimized by - * copying the map collection to a list. (This assumes that - * once an iterator is requested, it is likely that insertion into - * the map is complete). - */ - public Iterator iterator() - { - return getEdges().iterator(); - } - public List getEdges() - { - if (edgeList == null) { - edgeList = new ArrayList(edgeMap.values()); - } - return edgeList; - } - public EdgeEnd getNextCW(EdgeEnd ee) - { - getEdges(); - int i = edgeList.indexOf(ee); - int iNextCW = i - 1; - if (i == 0) - iNextCW = edgeList.size() - 1; - return (EdgeEnd) edgeList.get(iNextCW); - } - - public void computeLabelling(GeometryGraph[] geomGraph) - { - computeEdgeEndLabels(geomGraph[0].getBoundaryNodeRule()); - // Propagate side labels around the edges in the star - // for each parent Geometry -//Debug.print(this); - propagateSideLabels(0); -//Debug.print(this); -//Debug.printIfWatch(this); - propagateSideLabels(1); -//Debug.print(this); -//Debug.printIfWatch(this); - - /** - * If there are edges that still have null labels for a geometry - * this must be because there are no area edges for that geometry incident on this node. - * In this case, to label the edge for that geometry we must test whether the - * edge is in the interior of the geometry. - * To do this it suffices to determine whether the node for the edge is in the interior of an area. - * If so, the edge has location INTERIOR for the geometry. - * In all other cases (e.g. the node is on a line, on a point, or not on the geometry at all) the edge - * has the location EXTERIOR for the geometry. - *

                    - * Note that the edge cannot be on the BOUNDARY of the geometry, since then - * there would have been a parallel edge from the Geometry at this node also labelled BOUNDARY - * and this edge would have been labelled in the previous step. - *

                    - * This code causes a problem when dimensional collapses are present, since it may try and - * determine the location of a node where a dimensional collapse has occurred. - * The point should be considered to be on the EXTERIOR - * of the polygon, but locate() will return INTERIOR, since it is passed - * the original Geometry, not the collapsed version. - * - * If there are incident edges which are Line edges labelled BOUNDARY, - * then they must be edges resulting from dimensional collapses. - * In this case the other edges can be labelled EXTERIOR for this Geometry. - * - * MD 8/11/01 - NOT TRUE! The collapsed edges may in fact be in the interior of the Geometry, - * which means the other edges should be labelled INTERIOR for this Geometry. - * Not sure how solve this... Possibly labelling needs to be split into several phases: - * area label propagation, symLabel merging, then finally null label resolution. - */ - boolean[] hasDimensionalCollapseEdge = { false, false }; - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - Label label = e.getLabel(); - for (int geomi = 0; geomi < 2; geomi++) { - if (label.isLine(geomi) && label.getLocation(geomi) == Location.BOUNDARY) - hasDimensionalCollapseEdge[geomi] = true; - } - } -//Debug.print(this); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - Label label = e.getLabel(); -//Debug.println(e); - for (int geomi = 0; geomi < 2; geomi++) { - if (label.isAnyNull(geomi)) { - int loc = Location.NONE; - if (hasDimensionalCollapseEdge[geomi]) { - loc = Location.EXTERIOR; - } - else { - Coordinate p = e.getCoordinate(); - loc = getLocation(geomi, p, geomGraph); - } - label.setAllLocationsIfNull(geomi, loc); - } - } -//Debug.println(e); - } -//Debug.print(this); -//Debug.printIfWatch(this); - } - - private void computeEdgeEndLabels(BoundaryNodeRule boundaryNodeRule) - { - // Compute edge label for each EdgeEnd - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd ee = (EdgeEnd) it.next(); - ee.computeLabel(boundaryNodeRule); - } - } - - private int getLocation(int geomIndex, Coordinate p, GeometryGraph[] geom) - { - // compute location only on demand - if (ptInAreaLocation[geomIndex] == Location.NONE) { - ptInAreaLocation[geomIndex] = SimplePointInAreaLocator.locate(p, geom[geomIndex].getGeometry()); - } - return ptInAreaLocation[geomIndex]; - } - - public boolean isAreaLabelsConsistent(GeometryGraph geomGraph) - { - computeEdgeEndLabels(geomGraph.getBoundaryNodeRule()); - return checkAreaLabelsConsistent(0); - } - - private boolean checkAreaLabelsConsistent(int geomIndex) - { - // Since edges are stored in CCW order around the node, - // As we move around the ring we move from the right to the left side of the edge - List edges = getEdges(); - // if no edges, trivially consistent - if (edges.size() <= 0) - return true; - // initialize startLoc to location of last L side (if any) - int lastEdgeIndex = edges.size() - 1; - Label startLabel = ((EdgeEnd) edges.get(lastEdgeIndex)).getLabel(); - int startLoc = startLabel.getLocation(geomIndex, Position.LEFT); - Assert.isTrue(startLoc != Location.NONE, "Found unlabelled area edge"); - - int currLoc = startLoc; - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - Label label = e.getLabel(); - // we assume that we are only checking a area - Assert.isTrue(label.isArea(geomIndex), "Found non-area edge"); - int leftLoc = label.getLocation(geomIndex, Position.LEFT); - int rightLoc = label.getLocation(geomIndex, Position.RIGHT); -//System.out.println(leftLoc + " " + rightLoc); -//Debug.print(this); - // check that edge is really a boundary between inside and outside! - if (leftLoc == rightLoc) { - return false; - } - // check side location conflict - //Assert.isTrue(rightLoc == currLoc, "side location conflict " + locStr); - if (rightLoc != currLoc) { -//Debug.print(this); - return false; - } - currLoc = leftLoc; - } - return true; - } - void propagateSideLabels(int geomIndex) - { - // Since edges are stored in CCW order around the node, - // As we move around the ring we move from the right to the left side of the edge - int startLoc = Location.NONE ; - - // initialize loc to location of last L side (if any) -//System.out.println("finding start location"); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - Label label = e.getLabel(); - if (label.isArea(geomIndex) && label.getLocation(geomIndex, Position.LEFT) != Location.NONE) - startLoc = label.getLocation(geomIndex, Position.LEFT); - } - - // no labelled sides found, so no labels to propagate - if (startLoc == Location.NONE) return; - - int currLoc = startLoc; - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - Label label = e.getLabel(); - // set null ON values to be in current location - if (label.getLocation(geomIndex, Position.ON) == Location.NONE) - label.setLocation(geomIndex, Position.ON, currLoc); - // set side labels (if any) - if (label.isArea(geomIndex)) { - int leftLoc = label.getLocation(geomIndex, Position.LEFT); - int rightLoc = label.getLocation(geomIndex, Position.RIGHT); - // if there is a right location, that is the next location to propagate - if (rightLoc != Location.NONE) { -//Debug.print(rightLoc != currLoc, this); - if (rightLoc != currLoc) - throw new TopologyException("side location conflict", e.getCoordinate()); - if (leftLoc == Location.NONE) { - Assert.shouldNeverReachHere("found single null side (at " + e.getCoordinate() + ")"); - } - currLoc = leftLoc; - } - else { - /** RHS is null - LHS must be null too. - * This must be an edge from the other geometry, which has no location - * labelling for this geometry. This edge must lie wholly inside or outside - * the other geometry (which is determined by the current location). - * Assign both sides to be the current location. - */ - Assert.isTrue(label.getLocation(geomIndex, Position.LEFT) == Location.NONE, "found single null side"); - label.setLocation(geomIndex, Position.RIGHT, currLoc); - label.setLocation(geomIndex, Position.LEFT, currLoc); - } - } - } - } - - public int findIndex(EdgeEnd eSearch) - { - iterator(); // force edgelist to be computed - for (int i = 0; i < edgeList.size(); i++ ) { - EdgeEnd e = (EdgeEnd) edgeList.get(i); - if (e == eSearch) return i; - } - return -1; - } - - public void print(PrintStream out) - { - System.out.println("EdgeEndStar: " + getCoordinate()); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - e.print(out); - } - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("EdgeEndStar: " + getCoordinate()); - buf.append("\n"); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - buf.append(e); - buf.append("\n"); - } - return buf.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersection.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersection.java deleted file mode 100644 index d5fb7eea15..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersection.java +++ /dev/null @@ -1,107 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Represents a point on an - * edge which intersects with another edge. - *

                    - * The intersection may either be a single point, or a line segment - * (in which case this point is the start of the line segment) - * The intersection point must be precise. - * - * @version 1.7 - */ -public class EdgeIntersection - implements Comparable -{ - - public Coordinate coord; // the point of intersection - public int segmentIndex; // the index of the containing line segment in the parent edge - public double dist; // the edge distance of this point along the containing line segment - - public EdgeIntersection(Coordinate coord, int segmentIndex, double dist) { - this.coord = new Coordinate(coord); - this.segmentIndex = segmentIndex; - this.dist = dist; - } - - public Coordinate getCoordinate() { return coord; } - - public int getSegmentIndex() { return segmentIndex; } - - public double getDistance() { return dist; } - - public int compareTo(Object obj) - { - EdgeIntersection other = (EdgeIntersection) obj; - return compare(other.segmentIndex, other.dist); - } - /** - * @return -1 this EdgeIntersection is located before the argument location - * @return 0 this EdgeIntersection is at the argument location - * @return 1 this EdgeIntersection is located after the argument location - */ - public int compare(int segmentIndex, double dist) - { - if (this.segmentIndex < segmentIndex) return -1; - if (this.segmentIndex > segmentIndex) return 1; - if (this.dist < dist) return -1; - if (this.dist > dist) return 1; - return 0; - } - - public boolean isEndPoint(int maxSegmentIndex) - { - if (segmentIndex == 0 && dist == 0.0) return true; - if (segmentIndex == maxSegmentIndex) return true; - return false; - } - - public void print(PrintStream out) - { - out.print(coord); - out.print(" seg # = " + segmentIndex); - out.println(" dist = " + dist); - } - public String toString() - { - return coord + " seg # = " + segmentIndex + " dist = " + dist; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java deleted file mode 100644 index c4820d5e53..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import com.vividsolutions.jts.geom.*; -import java.io.*; -import java.util.*; - -/** - * A list of edge intersections along an {@link Edge}. - * Implements splitting an edge with intersections - * into multiple resultant edges. - * - * @version 1.7 - */ -public class EdgeIntersectionList -{ - // a Map - private Map nodeMap = new TreeMap(); - Edge edge; // the parent edge - - public EdgeIntersectionList(Edge edge) - { - this.edge = edge; - } - - /** - * Adds an intersection into the list, if it isn't already there. - * The input segmentIndex and dist are expected to be normalized. - * @return the EdgeIntersection found or added - */ - public EdgeIntersection add(Coordinate intPt, int segmentIndex, double dist) - { - EdgeIntersection eiNew = new EdgeIntersection(intPt, segmentIndex, dist); - EdgeIntersection ei = (EdgeIntersection) nodeMap.get(eiNew); - if (ei != null) { - return ei; - } - nodeMap.put(eiNew, eiNew); - return eiNew; - } - - /** - * Returns an iterator of {@link EdgeIntersection}s - * - * @return an Iterator of EdgeIntersections - */ - public Iterator iterator() { return nodeMap.values().iterator(); } - - /** - * Tests if the given point is an edge intersection - * - * @param pt the point to test - * @return true if the point is an intersection - */ - public boolean isIntersection(Coordinate pt) - { - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) it.next(); - if (ei.coord.equals(pt)) - return true; - } - return false; - } - - /** - * Adds entries for the first and last points of the edge to the list - */ - public void addEndpoints() - { - int maxSegIndex = edge.pts.length - 1; - add(edge.pts[0], 0, 0.0); - add(edge.pts[maxSegIndex], maxSegIndex, 0.0); - } - - /** - * Creates new edges for all the edges that the intersections in this - * list split the parent edge into. - * Adds the edges to the input list (this is so a single list - * can be used to accumulate all split edges for a Geometry). - * - * @param edgeList a list of EdgeIntersections - */ - public void addSplitEdges(List edgeList) - { - // ensure that the list has entries for the first and last point of the edge - addEndpoints(); - - Iterator it = iterator(); - // there should always be at least two entries in the list - EdgeIntersection eiPrev = (EdgeIntersection) it.next(); - while (it.hasNext()) { - EdgeIntersection ei = (EdgeIntersection) it.next(); - Edge newEdge = createSplitEdge(eiPrev, ei); - edgeList.add(newEdge); - - eiPrev = ei; - } - } - /** - * Create a new "split edge" with the section of points between - * (and including) the two intersections. - * The label for the new edge is the same as the label for the parent edge. - */ - Edge createSplitEdge(EdgeIntersection ei0, EdgeIntersection ei1) - { -//Debug.print("\ncreateSplitEdge"); Debug.print(ei0); Debug.print(ei1); - int npts = ei1.segmentIndex - ei0.segmentIndex + 2; - - Coordinate lastSegStartPt = edge.pts[ei1.segmentIndex]; - // if the last intersection point is not equal to the its segment start pt, - // add it to the points list as well. - // (This check is needed because the distance metric is not totally reliable!) - // The check for point equality is 2D only - Z values are ignored - boolean useIntPt1 = ei1.dist > 0.0 || ! ei1.coord.equals2D(lastSegStartPt); - if (! useIntPt1) { - npts--; - } - - Coordinate[] pts = new Coordinate[npts]; - int ipt = 0; - pts[ipt++] = new Coordinate(ei0.coord); - for (int i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) { - pts[ipt++] = edge.pts[i]; - } - if (useIntPt1) pts[ipt] = ei1.coord; - return new Edge(pts, new Label(edge.label)); - } - - public void print(PrintStream out) - { - out.println("Intersections:"); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) it.next(); - ei.print(out); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeList.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeList.java deleted file mode 100644 index 84e2391fff..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeList.java +++ /dev/null @@ -1,132 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import java.util.*; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.index.SpatialIndex; -import com.vividsolutions.jts.index.quadtree.Quadtree; -import com.vividsolutions.jts.noding.OrientedCoordinateArray; -import com.vividsolutions.jts.noding.SegmentString; - -/** - * A EdgeList is a list of Edges. It supports locating edges - * that are pointwise equals to a target edge. - * @version 1.7 - */ -public class EdgeList -{ - private List edges = new ArrayList(); - /** - * An index of the edges, for fast lookup. - * - */ - private Map ocaMap = new TreeMap(); - - public EdgeList() { - } - - /** - * Insert an edge unless it is already in the list - */ - public void add(Edge e) - { - edges.add(e); - OrientedCoordinateArray oca = new OrientedCoordinateArray(e.getCoordinates()); - ocaMap.put(oca, e); - } - - public void addAll(Collection edgeColl) - { - for (Iterator i = edgeColl.iterator(); i.hasNext(); ) { - add((Edge) i.next()); - } - } - - public List getEdges() { return edges; } - - /** - * If there is an edge equal to e already in the list, return it. - * Otherwise return null. - * @return equal edge, if there is one already in the list - * null otherwise - */ - public Edge findEqualEdge(Edge e) - { - OrientedCoordinateArray oca = new OrientedCoordinateArray(e.getCoordinates()); - // will return null if no edge matches - Edge matchEdge = (Edge) ocaMap.get(oca); - return matchEdge; - } - - public Iterator iterator() { return edges.iterator(); } - - public Edge get(int i) { return (Edge) edges.get(i); } - - /** - * If the edge e is already in the list, return its index. - * @return index, if e is already in the list - * -1 otherwise - */ - public int findEdgeIndex(Edge e) - { - for (int i = 0; i < edges.size(); i++) { - if ( ((Edge) edges.get(i)).equals(e) ) return i; - } - return -1; - } - - public void print(PrintStream out) - { - out.print("MULTILINESTRING ( "); - for (int j = 0; j < edges.size(); j++) { - Edge e = (Edge) edges.get(j); - if (j > 0) out.print(","); - out.print("("); - Coordinate[] pts = e.getCoordinates(); - for (int i = 0; i < pts.length; i++) { - if (i > 0) out.print(","); - out.print(pts[i].x + " " + pts[i].y); - } - out.println(")"); - } - out.print(") "); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java deleted file mode 100644 index af56c2da81..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java +++ /dev/null @@ -1,97 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.util.*; -import com.vividsolutions.jts.noding.*; - -/** - * Validates that a collection of {@link Edge}s is correctly noded. - * Throws an appropriate exception if an noding error is found. - * - * @version 1.7 - */ -public class EdgeNodingValidator -{ - /** - * Checks whether the supplied {@link Edge}s - * are correctly noded. - * Throws a {@link TopologyException} if they are not. - * - * @param edges a collection of Edges. - * @throws TopologyException if the SegmentStrings are not correctly noded - * - */ - public static void checkValid(Collection edges) - { - EdgeNodingValidator validator = new EdgeNodingValidator(edges); - validator.checkValid(); - } - - public static Collection toSegmentStrings(Collection edges) - { - // convert Edges to SegmentStrings - Collection segStrings = new ArrayList(); - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - segStrings.add(new BasicSegmentString(e.getCoordinates(), e)); - } - return segStrings; - } - - private FastNodingValidator nv; - - /** - * Creates a new validator for the given collection of {@link Edge}s. - * - * @param edges a collection of Edges. - */ - public EdgeNodingValidator(Collection edges) - { - nv = new FastNodingValidator(toSegmentStrings(edges)); - } - - /** - * Checks whether the supplied edges - * are correctly noded. Throws an exception if they are not. - * - * @throws TopologyException if the SegmentStrings are not correctly noded - * - */ - public void checkValid() - { - nv.checkValid(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeRing.java b/src/main/java/com/vividsolutions/jts/geomgraph/EdgeRing.java deleted file mode 100644 index 0dfa1dce47..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/EdgeRing.java +++ /dev/null @@ -1,246 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.impl.*; -import com.vividsolutions.jts.io.*; -import com.vividsolutions.jts.util.*; - - -/** - * @version 1.7 - */ -public abstract class EdgeRing { - - protected DirectedEdge startDe; // the directed edge which starts the list of edges for this EdgeRing - private int maxNodeDegree = -1; - private List edges = new ArrayList(); // the DirectedEdges making up this EdgeRing - private List pts = new ArrayList(); - private Label label = new Label(Location.NONE); // label stores the locations of each geometry on the face surrounded by this ring - private LinearRing ring; // the ring created for this EdgeRing - private boolean isHole; - private EdgeRing shell; // if non-null, the ring is a hole and this EdgeRing is its containing shell - private ArrayList holes = new ArrayList(); // a list of EdgeRings which are holes in this EdgeRing - - protected GeometryFactory geometryFactory; - - public EdgeRing(DirectedEdge start, GeometryFactory geometryFactory) { - this.geometryFactory = geometryFactory; - computePoints(start); - computeRing(); - } - - public boolean isIsolated() - { - return (label.getGeometryCount() == 1); - } - public boolean isHole() - { - //computePoints(); - return isHole; - } - - public Coordinate getCoordinate(int i) { return (Coordinate) pts.get(i); } - public LinearRing getLinearRing() { return ring; } - public Label getLabel() { return label; } - public boolean isShell() { return shell == null; } - public EdgeRing getShell() { return shell; } - public void setShell(EdgeRing shell) - { - this.shell = shell; - if (shell != null) shell.addHole(this); - } - public void addHole(EdgeRing ring) { holes.add(ring); } - - public Polygon toPolygon(GeometryFactory geometryFactory) - { - LinearRing[] holeLR = new LinearRing[holes.size()]; - for (int i = 0; i < holes.size(); i++) { - holeLR[i] = ((EdgeRing) holes.get(i)).getLinearRing(); - } - Polygon poly = geometryFactory.createPolygon(getLinearRing(), holeLR); - return poly; - } - /** - * Compute a LinearRing from the point list previously collected. - * Test if the ring is a hole (i.e. if it is CCW) and set the hole flag - * accordingly. - */ - public void computeRing() - { - if (ring != null) return; // don't compute more than once - Coordinate[] coord = new Coordinate[pts.size()]; - for (int i = 0; i < pts.size(); i++) { - coord[i] = (Coordinate) pts.get(i); - } - ring = geometryFactory.createLinearRing(coord); - isHole = CGAlgorithms.isCCW(ring.getCoordinates()); -//Debug.println( (isHole ? "hole - " : "shell - ") + WKTWriter.toLineString(new CoordinateArraySequence(ring.getCoordinates()))); - } - abstract public DirectedEdge getNext(DirectedEdge de); - abstract public void setEdgeRing(DirectedEdge de, EdgeRing er); - - /** - * Returns the list of DirectedEdges that make up this EdgeRing - */ - public List getEdges() { return edges; } - - /** - * Collect all the points from the DirectedEdges of this ring into a contiguous list - */ - protected void computePoints(DirectedEdge start) - { -//System.out.println("buildRing"); - startDe = start; - DirectedEdge de = start; - boolean isFirstEdge = true; - do { -// Assert.isTrue(de != null, "found null Directed Edge"); - if (de == null) - throw new TopologyException("Found null DirectedEdge"); - if (de.getEdgeRing() == this) - throw new TopologyException("Directed Edge visited twice during ring-building at " + de.getCoordinate()); - - edges.add(de); -//Debug.println(de); -//Debug.println(de.getEdge()); - Label label = de.getLabel(); - Assert.isTrue(label.isArea()); - mergeLabel(label); - addPoints(de.getEdge(), de.isForward(), isFirstEdge); - isFirstEdge = false; - setEdgeRing(de, this); - de = getNext(de); - } while (de != startDe); - } - - public int getMaxNodeDegree() - { - if (maxNodeDegree < 0) computeMaxNodeDegree(); - return maxNodeDegree; - } - - private void computeMaxNodeDegree() - { - maxNodeDegree = 0; - DirectedEdge de = startDe; - do { - Node node = de.getNode(); - int degree = ((DirectedEdgeStar) node.getEdges()).getOutgoingDegree(this); - if (degree > maxNodeDegree) maxNodeDegree = degree; - de = getNext(de); - } while (de != startDe); - maxNodeDegree *= 2; - } - - - public void setInResult() - { - DirectedEdge de = startDe; - do { - de.getEdge().setInResult(true); - de = de.getNext(); - } while (de != startDe); - } - - protected void mergeLabel(Label deLabel) - { - mergeLabel(deLabel, 0); - mergeLabel(deLabel, 1); - } - /** - * Merge the RHS label from a DirectedEdge into the label for this EdgeRing. - * The DirectedEdge label may be null. This is acceptable - it results - * from a node which is NOT an intersection node between the Geometries - * (e.g. the end node of a LinearRing). In this case the DirectedEdge label - * does not contribute any information to the overall labelling, and is simply skipped. - */ - protected void mergeLabel(Label deLabel, int geomIndex) - { - int loc = deLabel.getLocation(geomIndex, Position.RIGHT); - // no information to be had from this label - if (loc == Location.NONE) return; - // if there is no current RHS value, set it - if (label.getLocation(geomIndex) == Location.NONE) { - label.setLocation(geomIndex, loc); - return; - } - } - protected void addPoints(Edge edge, boolean isForward, boolean isFirstEdge) - { - Coordinate[] edgePts = edge.getCoordinates(); - if (isForward) { - int startIndex = 1; - if (isFirstEdge) startIndex = 0; - for (int i = startIndex; i < edgePts.length; i++) { - pts.add(edgePts[i]); - } - } - else { // is backward - int startIndex = edgePts.length - 2; - if (isFirstEdge) startIndex = edgePts.length - 1; - for (int i = startIndex; i >= 0; i--) { - pts.add(edgePts[i]); - } - } - } - - /** - * This method will cause the ring to be computed. - * It will also check any holes, if they have been assigned. - */ - public boolean containsPoint(Coordinate p) - { - LinearRing shell = getLinearRing(); - Envelope env = shell.getEnvelopeInternal(); - if (! env.contains(p)) return false; - if (! CGAlgorithms.isPointInRing(p, shell.getCoordinates()) ) return false; - - for (Iterator i = holes.iterator(); i.hasNext(); ) { - EdgeRing hole = (EdgeRing) i.next(); - if (hole.containsPoint(p) ) - return false; - } - return true; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/GeometryGraph.java b/src/main/java/com/vividsolutions/jts/geomgraph/GeometryGraph.java deleted file mode 100644 index cb66e5cfea..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/GeometryGraph.java +++ /dev/null @@ -1,459 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.algorithm.locate.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.index.*; -import com.vividsolutions.jts.util.*; - -/** - * A GeometryGraph is a graph that models a given Geometry - * @version 1.7 - */ -public class GeometryGraph - extends PlanarGraph -{ -/** - * This method implements the Boundary Determination Rule - * for determining whether - * a component (node or edge) that appears multiple times in elements - * of a MultiGeometry is in the boundary or the interior of the Geometry - *
                    - * The SFS uses the "Mod-2 Rule", which this function implements - *
                    - * An alternative (and possibly more intuitive) rule would be - * the "At Most One Rule": - * isInBoundary = (componentCount == 1) - */ -/* - public static boolean isInBoundary(int boundaryCount) - { - // the "Mod-2 Rule" - return boundaryCount % 2 == 1; - } - public static int determineBoundary(int boundaryCount) - { - return isInBoundary(boundaryCount) ? Location.BOUNDARY : Location.INTERIOR; - } -*/ - - public static int determineBoundary(BoundaryNodeRule boundaryNodeRule, int boundaryCount) - { - return boundaryNodeRule.isInBoundary(boundaryCount) - ? Location.BOUNDARY : Location.INTERIOR; - } - - private Geometry parentGeom; - - /** - * The lineEdgeMap is a map of the linestring components of the - * parentGeometry to the edges which are derived from them. - * This is used to efficiently perform findEdge queries - */ - private Map lineEdgeMap = new HashMap(); - - private BoundaryNodeRule boundaryNodeRule = null; - - /** - * If this flag is true, the Boundary Determination Rule will used when deciding - * whether nodes are in the boundary or not - */ - private boolean useBoundaryDeterminationRule = true; - private int argIndex; // the index of this geometry as an argument to a spatial function (used for labelling) - private Collection boundaryNodes; - private boolean hasTooFewPoints = false; - private Coordinate invalidPoint = null; - - private PointOnGeometryLocator areaPtLocator = null; - // for use if geometry is not Polygonal - private final PointLocator ptLocator = new PointLocator(); - - private EdgeSetIntersector createEdgeSetIntersector() - { - // various options for computing intersections, from slowest to fastest - - //private EdgeSetIntersector esi = new SimpleEdgeSetIntersector(); - //private EdgeSetIntersector esi = new MonotoneChainIntersector(); - //private EdgeSetIntersector esi = new NonReversingChainIntersector(); - //private EdgeSetIntersector esi = new SimpleSweepLineIntersector(); - //private EdgeSetIntersector esi = new MCSweepLineIntersector(); - - //return new SimpleEdgeSetIntersector(); - return new SimpleMCSweepLineIntersector(); - } - - public GeometryGraph(int argIndex, Geometry parentGeom) - { - this(argIndex, parentGeom, - BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE - ); - } - - public GeometryGraph(int argIndex, Geometry parentGeom, BoundaryNodeRule boundaryNodeRule) { - this.argIndex = argIndex; - this.parentGeom = parentGeom; - this.boundaryNodeRule = boundaryNodeRule; - if (parentGeom != null) { -// precisionModel = parentGeom.getPrecisionModel(); -// SRID = parentGeom.getSRID(); - add(parentGeom); - } - } - - /** - * This constructor is used by clients that wish to add Edges explicitly, - * rather than adding a Geometry. (An example is BufferOp). - */ - // no longer used -// public GeometryGraph(int argIndex, PrecisionModel precisionModel, int SRID) { -// this(argIndex, null); -// this.precisionModel = precisionModel; -// this.SRID = SRID; -// } -// public PrecisionModel getPrecisionModel() -// { -// return precisionModel; -// } -// public int getSRID() { return SRID; } - - public boolean hasTooFewPoints() { return hasTooFewPoints; } - - public Coordinate getInvalidPoint() { return invalidPoint; } - - public Geometry getGeometry() { return parentGeom; } - - public BoundaryNodeRule getBoundaryNodeRule() { return boundaryNodeRule; } - - public Collection getBoundaryNodes() - { - if (boundaryNodes == null) - boundaryNodes = nodes.getBoundaryNodes(argIndex); - return boundaryNodes; - } - - public Coordinate[] getBoundaryPoints() - { - Collection coll = getBoundaryNodes(); - Coordinate[] pts = new Coordinate[coll.size()]; - int i = 0; - for (Iterator it = coll.iterator(); it.hasNext(); ) { - Node node = (Node) it.next(); - pts[i++] = (Coordinate) node.getCoordinate().clone(); - } - return pts; - } - - public Edge findEdge(LineString line) - { - return (Edge) lineEdgeMap.get(line); - } - - public void computeSplitEdges(List edgelist) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - e.eiList.addSplitEdges(edgelist); - } - } - private void add(Geometry g) - { - if (g.isEmpty()) return; - - // check if this Geometry should obey the Boundary Determination Rule - // all collections except MultiPolygons obey the rule - if (g instanceof MultiPolygon) - useBoundaryDeterminationRule = false; - - if (g instanceof Polygon) addPolygon((Polygon) g); - // LineString also handles LinearRings - else if (g instanceof LineString) addLineString((LineString) g); - else if (g instanceof Point) addPoint((Point) g); - else if (g instanceof MultiPoint) addCollection((MultiPoint) g); - else if (g instanceof MultiLineString) addCollection((MultiLineString) g); - else if (g instanceof MultiPolygon) addCollection((MultiPolygon) g); - else if (g instanceof GeometryCollection) addCollection((GeometryCollection) g); - else throw new UnsupportedOperationException(g.getClass().getName()); - } - - private void addCollection(GeometryCollection gc) - { - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - add(g); - } - } - /** - * Add a Point to the graph. - */ - private void addPoint(Point p) - { - Coordinate coord = p.getCoordinate(); - insertPoint(argIndex, coord, Location.INTERIOR); - } - - /** - * Adds a polygon ring to the graph. - * Empty rings are ignored. - * - * The left and right topological location arguments assume that the ring is oriented CW. - * If the ring is in the opposite orientation, - * the left and right locations must be interchanged. - */ - private void addPolygonRing(LinearRing lr, int cwLeft, int cwRight) - { - // don't bother adding empty holes - if (lr.isEmpty()) return; - - Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(lr.getCoordinates()); - - if (coord.length < 4) { - hasTooFewPoints = true; - invalidPoint = coord[0]; - return; - } - - int left = cwLeft; - int right = cwRight; - if (CGAlgorithms.isCCW(coord)) { - left = cwRight; - right = cwLeft; - } - Edge e = new Edge(coord, - new Label(argIndex, Location.BOUNDARY, left, right)); - lineEdgeMap.put(lr, e); - - insertEdge(e); - // insert the endpoint as a node, to mark that it is on the boundary - insertPoint(argIndex, coord[0], Location.BOUNDARY); - } - - private void addPolygon(Polygon p) - { - addPolygonRing( - (LinearRing) p.getExteriorRing(), - Location.EXTERIOR, - Location.INTERIOR); - - for (int i = 0; i < p.getNumInteriorRing(); i++) { - LinearRing hole = (LinearRing) p.getInteriorRingN(i); - - // Holes are topologically labelled opposite to the shell, since - // the interior of the polygon lies on their opposite side - // (on the left, if the hole is oriented CW) - addPolygonRing( - hole, - Location.INTERIOR, - Location.EXTERIOR); - } - } - - private void addLineString(LineString line) - { - Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates()); - - if (coord.length < 2) { - hasTooFewPoints = true; - invalidPoint = coord[0]; - return; - } - - // add the edge for the LineString - // line edges do not have locations for their left and right sides - Edge e = new Edge(coord, new Label(argIndex, Location.INTERIOR)); - lineEdgeMap.put(line, e); - insertEdge(e); - /** - * Add the boundary points of the LineString, if any. - * Even if the LineString is closed, add both points as if they were endpoints. - * This allows for the case that the node already exists and is a boundary point. - */ - Assert.isTrue(coord.length >= 2, "found LineString with single point"); - insertBoundaryPoint(argIndex, coord[0]); - insertBoundaryPoint(argIndex, coord[coord.length - 1]); - - } - - /** - * Add an Edge computed externally. The label on the Edge is assumed - * to be correct. - */ - public void addEdge(Edge e) - { - insertEdge(e); - Coordinate[] coord = e.getCoordinates(); - // insert the endpoint as a node, to mark that it is on the boundary - insertPoint(argIndex, coord[0], Location.BOUNDARY); - insertPoint(argIndex, coord[coord.length - 1], Location.BOUNDARY); - } - - /** - * Add a point computed externally. The point is assumed to be a - * Point Geometry part, which has a location of INTERIOR. - */ - public void addPoint(Coordinate pt) - { - insertPoint(argIndex, pt, Location.INTERIOR); - } - - /** - * Compute self-nodes, taking advantage of the Geometry type to - * minimize the number of intersection tests. (E.g. rings are - * not tested for self-intersection, since they are assumed to be valid). - * @param li the LineIntersector to use - * @param computeRingSelfNodes if , intersection checks are optimized to not test rings for self-intersection - * @return the SegmentIntersector used, containing information about the intersections found - */ - public SegmentIntersector computeSelfNodes(LineIntersector li, boolean computeRingSelfNodes) - { - SegmentIntersector si = new SegmentIntersector(li, true, false); - EdgeSetIntersector esi = createEdgeSetIntersector(); - // optimized test for Polygons and Rings - if (! computeRingSelfNodes - && (parentGeom instanceof LinearRing - || parentGeom instanceof Polygon - || parentGeom instanceof MultiPolygon)) { - esi.computeIntersections(edges, si, false); - } - else { - esi.computeIntersections(edges, si, true); - } -//System.out.println("SegmentIntersector # tests = " + si.numTests); - addSelfIntersectionNodes(argIndex); - return si; - } - - public SegmentIntersector computeEdgeIntersections( - GeometryGraph g, - LineIntersector li, - boolean includeProper) - { - SegmentIntersector si = new SegmentIntersector(li, includeProper, true); - si.setBoundaryNodes(this.getBoundaryNodes(), g.getBoundaryNodes()); - - EdgeSetIntersector esi = createEdgeSetIntersector(); - esi.computeIntersections(edges, g.edges, si); -/* -for (Iterator i = g.edges.iterator(); i.hasNext();) { -Edge e = (Edge) i.next(); -Debug.print(e.getEdgeIntersectionList()); -} -*/ - return si; - } - - private void insertPoint(int argIndex, Coordinate coord, int onLocation) - { - Node n = nodes.addNode(coord); - Label lbl = n.getLabel(); - if (lbl == null) { - n.label = new Label(argIndex, onLocation); - } - else - lbl.setLocation(argIndex, onLocation); - } - - /** - * Adds candidate boundary points using the current {@link BoundaryNodeRule}. - * This is used to add the boundary - * points of dim-1 geometries (Curves/MultiCurves). - */ - private void insertBoundaryPoint(int argIndex, Coordinate coord) - { - Node n = nodes.addNode(coord); - // nodes always have labels - Label lbl = n.getLabel(); - // the new point to insert is on a boundary - int boundaryCount = 1; - // determine the current location for the point (if any) - int loc = Location.NONE; - loc = lbl.getLocation(argIndex, Position.ON); - if (loc == Location.BOUNDARY) boundaryCount++; - - // determine the boundary status of the point according to the Boundary Determination Rule - int newLoc = determineBoundary(boundaryNodeRule, boundaryCount); - lbl.setLocation(argIndex, newLoc); - } - - private void addSelfIntersectionNodes(int argIndex) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - int eLoc = e.getLabel().getLocation(argIndex); - for (Iterator eiIt = e.eiList.iterator(); eiIt.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) eiIt.next(); - addSelfIntersectionNode(argIndex, ei.coord, eLoc); - } - } - } - /** - * Add a node for a self-intersection. - * If the node is a potential boundary node (e.g. came from an edge which - * is a boundary) then insert it as a potential boundary node. - * Otherwise, just add it as a regular node. - */ - private void addSelfIntersectionNode(int argIndex, Coordinate coord, int loc) - { - // if this node is already a boundary node, don't change it - if (isBoundaryNode(argIndex, coord)) return; - if (loc == Location.BOUNDARY && useBoundaryDeterminationRule) - insertBoundaryPoint(argIndex, coord); - else - insertPoint(argIndex, coord, loc); - } - - // MD - experimental for now - /** - * Determines the {@link Location} of the given {@link Coordinate} - * in this geometry. - * - * @param p the point to test - * @return the location of the point in the geometry - */ - public int locate(Coordinate pt) - { - if (parentGeom instanceof Polygonal && parentGeom.getNumGeometries() > 50) { - // lazily init point locator - if (areaPtLocator == null) { - areaPtLocator = new IndexedPointInAreaLocator(parentGeom); - } - return areaPtLocator.locate(pt); - } - return ptLocator.locate(pt, parentGeom); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/GraphComponent.java b/src/main/java/com/vividsolutions/jts/geomgraph/GraphComponent.java deleted file mode 100644 index 4ebcf29051..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/GraphComponent.java +++ /dev/null @@ -1,107 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.Label; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.IntersectionMatrix; -import com.vividsolutions.jts.util.Assert; - -/** - * A GraphComponent is the parent class for the objects' - * that form a graph. Each GraphComponent can carry a - * Label. - * @version 1.7 - */ -abstract public class GraphComponent { - - protected Label label; - /** - * isInResult indicates if this component has already been included in the result - */ - private boolean isInResult = false; - private boolean isCovered = false; - private boolean isCoveredSet = false; - private boolean isVisited = false; - - public GraphComponent() { - } - - public GraphComponent(Label label) { - this.label = label; - } - - public Label getLabel() { return label; } - public void setLabel(Label label) { this.label = label; } - public void setInResult(boolean isInResult) { this.isInResult = isInResult; } - public boolean isInResult() { return isInResult; } - public void setCovered(boolean isCovered) - { - this.isCovered = isCovered; - this.isCoveredSet = true; - } - public boolean isCovered() { return isCovered; } - public boolean isCoveredSet() { return isCoveredSet; } - public boolean isVisited() { return isVisited; } - public void setVisited(boolean isVisited) { this.isVisited = isVisited; } - /** - * @return a coordinate in this component (or null, if there are none) - */ - abstract public Coordinate getCoordinate(); - /** - * compute the contribution to an IM for this component - */ - abstract protected void computeIM(IntersectionMatrix im); - /** - * An isolated component is one that does not intersect or touch any other - * component. This is the case if the label has valid locations for - * only a single Geometry. - * - * @return true if this component is isolated - */ - abstract public boolean isIsolated(); - /** - * Update the IM with the contribution for this component. - * A component only contributes if it has a labelling for both parent geometries - */ - public void updateIM(IntersectionMatrix im) - { - Assert.isTrue(label.getGeometryCount() >= 2, "found partial label"); - computeIM(im); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Label.java b/src/main/java/com/vividsolutions/jts/geomgraph/Label.java deleted file mode 100644 index 7f1377b373..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Label.java +++ /dev/null @@ -1,222 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import com.vividsolutions.jts.geom.Location; - - /** - * A Label indicates the topological relationship of a component - * of a topology graph to a given Geometry. - * This class supports labels for relationships to two Geometrys, - * which is sufficient for algorithms for binary operations. - *

                    - * Topology graphs support the concept of labeling nodes and edges in the graph. - * The label of a node or edge specifies its topological relationship to one or - * more geometries. (In fact, since JTS operations have only two arguments labels - * are required for only two geometries). A label for a node or edge has one or - * two elements, depending on whether the node or edge occurs in one or both of the - * input Geometrys. Elements contain attributes which categorize the - * topological location of the node or edge relative to the parent - * Geometry; that is, whether the node or edge is in the interior, - * boundary or exterior of the Geometry. Attributes have a value - * from the set {Interior, Boundary, Exterior}. In a node each - * element has a single attribute <On>. For an edge each element has a - * triplet of attributes <Left, On, Right>. - *

                    - * It is up to the client code to associate the 0 and 1 TopologyLocations - * with specific geometries. - * @version 1.7 - * - */ -public class Label { - - // converts a Label to a Line label (that is, one with no side Locations) - public static Label toLineLabel(Label label) - { - Label lineLabel = new Label(Location.NONE); - for (int i = 0; i < 2; i++) { - lineLabel.setLocation(i, label.getLocation(i)); - } - return lineLabel; - } - - TopologyLocation elt[] = new TopologyLocation[2]; - - /** - * Construct a Label with a single location for both Geometries. - * Initialize the locations to Null - */ - public Label(int onLoc) - { - elt[0] = new TopologyLocation(onLoc); - elt[1] = new TopologyLocation(onLoc); - } - /** - * Construct a Label with a single location for both Geometries. - * Initialize the location for the Geometry index. - */ - public Label(int geomIndex, int onLoc) - { - elt[0] = new TopologyLocation(Location.NONE); - elt[1] = new TopologyLocation(Location.NONE); - elt[geomIndex].setLocation(onLoc); - } - /** - * Construct a Label with On, Left and Right locations for both Geometries. - * Initialize the locations for both Geometries to the given values. - */ - public Label(int onLoc, int leftLoc, int rightLoc) - { - elt[0] = new TopologyLocation(onLoc, leftLoc, rightLoc); - elt[1] = new TopologyLocation(onLoc, leftLoc, rightLoc); - } - /** - * Construct a Label with On, Left and Right locations for both Geometries. - * Initialize the locations for the given Geometry index. - */ - public Label(int geomIndex, int onLoc, int leftLoc, int rightLoc) - { - elt[0] = new TopologyLocation(Location.NONE, Location.NONE, Location.NONE); - elt[1] = new TopologyLocation(Location.NONE, Location.NONE, Location.NONE); - elt[geomIndex].setLocations(onLoc, leftLoc, rightLoc); - } - /** - * Construct a Label with the same values as the argument Label. - */ - public Label(Label lbl) - { - elt[0] = new TopologyLocation(lbl.elt[0]); - elt[1] = new TopologyLocation(lbl.elt[1]); - } - - public void flip() - { - elt[0].flip(); - elt[1].flip(); - } - - public int getLocation(int geomIndex, int posIndex) { return elt[geomIndex].get(posIndex); } - public int getLocation(int geomIndex) { return elt[geomIndex].get(Position.ON); } - public void setLocation(int geomIndex, int posIndex, int location) - { - elt[geomIndex].setLocation(posIndex, location); - } - public void setLocation(int geomIndex, int location) - { - elt[geomIndex].setLocation(Position.ON, location); - } - public void setAllLocations(int geomIndex, int location) - { - elt[geomIndex].setAllLocations(location); - } - public void setAllLocationsIfNull(int geomIndex, int location) - { - elt[geomIndex].setAllLocationsIfNull(location); - } - public void setAllLocationsIfNull(int location) - { - setAllLocationsIfNull(0, location); - setAllLocationsIfNull(1, location); - } - /** - * Merge this label with another one. - * Merging updates any null attributes of this label with the attributes from lbl - */ - public void merge(Label lbl) - { - for (int i = 0; i < 2; i++) { - if (elt[i] == null && lbl.elt[i] != null) { - elt[i] = new TopologyLocation(lbl.elt[i]); - } - else { - elt[i].merge(lbl.elt[i]); - } - } - } - public int getGeometryCount() - { - int count = 0; - if (! elt[0].isNull()) count++; - if (! elt[1].isNull()) count++; - return count; - } - public boolean isNull(int geomIndex) { return elt[geomIndex].isNull(); } - public boolean isAnyNull(int geomIndex) { return elt[geomIndex].isAnyNull(); } - - public boolean isArea() { return elt[0].isArea() || elt[1].isArea(); } - public boolean isArea(int geomIndex) - { - /* Testing - if (elt[0].getLocations().length != elt[1].getLocations().length) { - System.out.println(this); - } - */ - return elt[geomIndex].isArea(); - } - public boolean isLine(int geomIndex) { return elt[geomIndex].isLine(); } - - public boolean isEqualOnSide(Label lbl, int side) - { - return - this.elt[0].isEqualOnSide(lbl.elt[0], side) - && this.elt[1].isEqualOnSide(lbl.elt[1], side); - } - public boolean allPositionsEqual(int geomIndex, int loc) - { - return elt[geomIndex].allPositionsEqual(loc); - } - /** - * Converts one GeometryLocation to a Line location - */ - public void toLine(int geomIndex) - { - if (elt[geomIndex].isArea()) - elt[geomIndex] = new TopologyLocation(elt[geomIndex].location[0]); - } - public String toString() - { - StringBuffer buf = new StringBuffer(); - if (elt[0] != null) { - buf.append("A:"); - buf.append(elt[0].toString()); - } - if (elt[1] != null) { - buf.append(" B:"); - buf.append(elt[1].toString()); - } - return buf.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Node.java b/src/main/java/com/vividsolutions/jts/geomgraph/Node.java deleted file mode 100644 index 3aebf21c78..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Node.java +++ /dev/null @@ -1,177 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.IntersectionMatrix; -import com.vividsolutions.jts.geom.Location; -import com.vividsolutions.jts.geomgraph.GraphComponent; -import com.vividsolutions.jts.geomgraph.Label; -import com.vividsolutions.jts.util.*; - - -/** - * @version 1.7 - */ -public class Node - extends GraphComponent -{ - protected Coordinate coord; // only non-null if this node is precise - protected EdgeEndStar edges; - - public Node(Coordinate coord, EdgeEndStar edges) - { - this.coord = coord; - this.edges = edges; - label = new Label(0, Location.NONE); - } - - public Coordinate getCoordinate() { return coord; } - public EdgeEndStar getEdges() { return edges; } - - /** - * Tests whether any incident edge is flagged as - * being in the result. - * This test can be used to determine if the node is in the result, - * since if any incident edge is in the result, the node must be in the result as well. - * - * @return true if any indicident edge in the in the result - */ - public boolean isIncidentEdgeInResult() - { - for (Iterator it = getEdges().getEdges().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.getEdge().isInResult()) - return true; - } - return false; - } - - public boolean isIsolated() - { - return (label.getGeometryCount() == 1); - } - /** - * Basic nodes do not compute IMs - */ - protected void computeIM(IntersectionMatrix im) {} - /** - * Add the edge to the list of edges at this node - */ - public void add(EdgeEnd e) - { - // Assert: start pt of e is equal to node point - edges.insert(e); - e.setNode(this); - } - - public void mergeLabel(Node n) - { - mergeLabel(n.label); - } - - /** - * To merge labels for two nodes, - * the merged location for each LabelElement is computed. - * The location for the corresponding node LabelElement is set to the result, - * as long as the location is non-null. - */ - - public void mergeLabel(Label label2) - { - for (int i = 0; i < 2; i++) { - int loc = computeMergedLocation(label2, i); - int thisLoc = label.getLocation(i); - if (thisLoc == Location.NONE) label.setLocation(i, loc); - } - } - - public void setLabel(int argIndex, int onLocation) - { - if (label == null) { - label = new Label(argIndex, onLocation); - } - else - label.setLocation(argIndex, onLocation); - } - - /** - * Updates the label of a node to BOUNDARY, - * obeying the mod-2 boundaryDetermination rule. - */ - public void setLabelBoundary(int argIndex) - { - if (label == null) return; - - // determine the current location for the point (if any) - int loc = Location.NONE; - if (label != null) - loc = label.getLocation(argIndex); - // flip the loc - int newLoc; - switch (loc) { - case Location.BOUNDARY: newLoc = Location.INTERIOR; break; - case Location.INTERIOR: newLoc = Location.BOUNDARY; break; - default: newLoc = Location.BOUNDARY; break; - } - label.setLocation(argIndex, newLoc); - } - - /** - * The location for a given eltIndex for a node will be one - * of { null, INTERIOR, BOUNDARY }. - * A node may be on both the boundary and the interior of a geometry; - * in this case, the rule is that the node is considered to be in the boundary. - * The merged location is the maximum of the two input values. - */ - int computeMergedLocation(Label label2, int eltIndex) - { - int loc = Location.NONE; - loc = label.getLocation(eltIndex); - if (! label2.isNull(eltIndex)) { - int nLoc = label2.getLocation(eltIndex); - if (loc != Location.BOUNDARY) loc = nLoc; - } - return loc; - } - - public void print(PrintStream out) - { - out.println("node " + coord + " lbl: " + label); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/NodeFactory.java b/src/main/java/com/vividsolutions/jts/geomgraph/NodeFactory.java deleted file mode 100644 index d06f315851..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/NodeFactory.java +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -import com.vividsolutions.jts.geom.Coordinate; - - -/** - * @version 1.7 - */ -public class NodeFactory { -/** - * The basic node constructor does not allow for incident edges - */ - public Node createNode(Coordinate coord) - { - return new Node(coord, null); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/NodeMap.java b/src/main/java/com/vividsolutions/jts/geomgraph/NodeMap.java deleted file mode 100644 index 60859d9a51..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/NodeMap.java +++ /dev/null @@ -1,137 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Location; -import com.vividsolutions.jts.geomgraph.Node; - -/** - * A map of nodes, indexed by the coordinate of the node - * @version 1.7 - */ -public class NodeMap - -{ - //Map nodeMap = new HashMap(); - Map nodeMap = new TreeMap(); - NodeFactory nodeFact; - - public NodeMap(NodeFactory nodeFact) { - this.nodeFact = nodeFact; - } - - /** - * Factory function - subclasses can override to create their own types of nodes - */ - /* - protected Node createNode(Coordinate coord) - { - return new Node(coord); - } - */ - /** - * This method expects that a node has a coordinate value. - */ - public Node addNode(Coordinate coord) - { - Node node = (Node) nodeMap.get(coord); - if (node == null) { - node = nodeFact.createNode(coord); - nodeMap.put(coord, node); - } - return node; - } - - public Node addNode(Node n) - { - Node node = (Node) nodeMap.get(n.getCoordinate()); - if (node == null) { - nodeMap.put(n.getCoordinate(), n); - return n; - } - node.mergeLabel(n); - return node; - } - - /** - * Adds a node for the start point of this EdgeEnd - * (if one does not already exist in this map). - * Adds the EdgeEnd to the (possibly new) node. - */ - public void add(EdgeEnd e) - { - Coordinate p = e.getCoordinate(); - Node n = addNode(p); - n.add(e); - } - /** - * @return the node if found; null otherwise - */ - public Node find(Coordinate coord) { return (Node) nodeMap.get(coord); } - - public Iterator iterator() - { - return nodeMap.values().iterator(); - } - public Collection values() - { - return nodeMap.values(); - } - - public Collection getBoundaryNodes(int geomIndex) - { - Collection bdyNodes = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (node.getLabel().getLocation(geomIndex) == Location.BOUNDARY) - bdyNodes.add(node); - } - return bdyNodes; - } - - public void print(PrintStream out) - { - for (Iterator it = iterator(); it.hasNext(); ) - { - Node n = (Node) it.next(); - n.print(out); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/PlanarGraph.java b/src/main/java/com/vividsolutions/jts/geomgraph/PlanarGraph.java deleted file mode 100644 index 779ff06d0a..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/PlanarGraph.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -/** - * @version 1.7 - */ -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; - -/** - * The computation of the IntersectionMatrix relies on the use of a structure - * called a "topology graph". The topology graph contains nodes and edges - * corresponding to the nodes and line segments of a Geometry. Each - * node and edge in the graph is labeled with its topological location relative to - * the source geometry. - *

                    - * Note that there is no requirement that points of self-intersection be a vertex. - * Thus to obtain a correct topology graph, Geometrys must be - * self-noded before constructing their graphs. - *

                    - * Two fundamental operations are supported by topology graphs: - *

                      - *
                    • Computing the intersections between all the edges and nodes of a single graph - *
                    • Computing the intersections between the edges and nodes of two different graphs - *
                    - * - * @version 1.7 - */ -public class PlanarGraph -{ - /** - * For nodes in the Collection, link the DirectedEdges at the node that are in the result. - * This allows clients to link only a subset of nodes in the graph, for - * efficiency (because they know that only a subset is of interest). - */ - public static void linkResultDirectedEdges(Collection nodes) - { - for (Iterator nodeit = nodes.iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - ((DirectedEdgeStar) node.getEdges()).linkResultDirectedEdges(); - } - } - - protected List edges = new ArrayList(); - protected NodeMap nodes; - protected List edgeEndList = new ArrayList(); - - public PlanarGraph(NodeFactory nodeFact) { - nodes = new NodeMap(nodeFact); - } - - public PlanarGraph() { - nodes = new NodeMap(new NodeFactory()); - } - - public Iterator getEdgeIterator() { return edges.iterator(); } - public Collection getEdgeEnds() { return edgeEndList; } - - public boolean isBoundaryNode(int geomIndex, Coordinate coord) - { - Node node = nodes.find(coord); - if (node == null) return false; - Label label = node.getLabel(); - if (label != null && label.getLocation(geomIndex) == Location.BOUNDARY) return true; - return false; - } - protected void insertEdge(Edge e) - { - edges.add(e); - } - public void add(EdgeEnd e) - { - nodes.add(e); - edgeEndList.add(e); - } - - public Iterator getNodeIterator() { return nodes.iterator(); } - public Collection getNodes() { return nodes.values(); } - public Node addNode(Node node) { return nodes.addNode(node); } - public Node addNode(Coordinate coord) { return nodes.addNode(coord); } - /** - * @return the node if found; null otherwise - */ - public Node find(Coordinate coord) { return nodes.find(coord); } - - /** - * Add a set of edges to the graph. For each edge two DirectedEdges - * will be created. DirectedEdges are NOT linked by this method. - */ - public void addEdges(List edgesToAdd) - { - // create all the nodes for the edges - for (Iterator it = edgesToAdd.iterator(); it.hasNext(); ) { - Edge e = (Edge) it.next(); - edges.add(e); - - DirectedEdge de1 = new DirectedEdge(e, true); - DirectedEdge de2 = new DirectedEdge(e, false); - de1.setSym(de2); - de2.setSym(de1); - - add(de1); - add(de2); - } - } - - /** - * Link the DirectedEdges at the nodes of the graph. - * This allows clients to link only a subset of nodes in the graph, for - * efficiency (because they know that only a subset is of interest). - */ - public void linkResultDirectedEdges() - { - for (Iterator nodeit = nodes.iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - ((DirectedEdgeStar) node.getEdges()).linkResultDirectedEdges(); - } - } - /** - * Link the DirectedEdges at the nodes of the graph. - * This allows clients to link only a subset of nodes in the graph, for - * efficiency (because they know that only a subset is of interest). - */ - public void linkAllDirectedEdges() - { - for (Iterator nodeit = nodes.iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - ((DirectedEdgeStar) node.getEdges()).linkAllDirectedEdges(); - } - } - /** - * Returns the EdgeEnd which has edge e as its base edge - * (MD 18 Feb 2002 - this should return a pair of edges) - * - * @return the edge, if found - * null if the edge was not found - */ - public EdgeEnd findEdgeEnd(Edge e) - { - for (Iterator i = getEdgeEnds().iterator(); i.hasNext(); ) { - EdgeEnd ee = (EdgeEnd) i.next(); - if (ee.getEdge() == e) - return ee; - } - return null; - } - - /** - * Returns the edge whose first two coordinates are p0 and p1 - * - * @return the edge, if found - * null if the edge was not found - */ - public Edge findEdge(Coordinate p0, Coordinate p1) - { - for (int i = 0; i < edges.size(); i++) { - Edge e = (Edge) edges.get(i); - Coordinate[] eCoord = e.getCoordinates(); - if (p0.equals(eCoord[0]) && p1.equals(eCoord[1]) ) - return e; - } - return null; - } - /** - * Returns the edge which starts at p0 and whose first segment is - * parallel to p1 - * - * @return the edge, if found - * null if the edge was not found - */ - public Edge findEdgeInSameDirection(Coordinate p0, Coordinate p1) - { - for (int i = 0; i < edges.size(); i++) { - Edge e = (Edge) edges.get(i); - - Coordinate[] eCoord = e.getCoordinates(); - if (matchInSameDirection(p0, p1, eCoord[0], eCoord[1]) ) - return e; - - if (matchInSameDirection(p0, p1, eCoord[eCoord.length - 1], eCoord[eCoord.length - 2]) ) - return e; - } - return null; - } - - /** - * The coordinate pairs match if they define line segments lying in the same direction. - * E.g. the segments are parallel and in the same quadrant - * (as opposed to parallel and opposite!). - */ - private boolean matchInSameDirection(Coordinate p0, Coordinate p1, Coordinate ep0, Coordinate ep1) - { - if (! p0.equals(ep0)) - return false; - - if (CGAlgorithms.computeOrientation(p0, p1, ep1) == CGAlgorithms.COLLINEAR - && Quadrant.quadrant(p0, p1) == Quadrant.quadrant(ep0, ep1) ) - return true; - return false; - } - - public void printEdges(PrintStream out) - { - out.println("Edges:"); - for (int i = 0; i < edges.size(); i++) { - out.println("edge " + i + ":"); - Edge e = (Edge) edges.get(i); - e.print(out); - e.eiList.print(out); - } - } - void debugPrint(Object o) - { - System.out.print(o); - } - void debugPrintln(Object o) - { - System.out.println(o); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Position.java b/src/main/java/com/vividsolutions/jts/geomgraph/Position.java deleted file mode 100644 index 0b2fde0653..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Position.java +++ /dev/null @@ -1,61 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -/** - * A Position indicates the position of a Location relative to a graph component - * (Node, Edge, or Area). - * @version 1.7 - */ -public class Position { - - /** An indicator that a Location is on a GraphComponent */ - public static final int ON = 0; - /** An indicator that a Location is to the left of a GraphComponent */ - public static final int LEFT = 1; - /** An indicator that a Location is to the right of a GraphComponent */ - public static final int RIGHT = 2; - /** - * Returns LEFT if the position is RIGHT, RIGHT if the position is LEFT, or the position - * otherwise. - */ - public static final int opposite(int position) - { - if (position == LEFT) return RIGHT; - if (position == RIGHT) return LEFT; - return position; - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/Quadrant.java b/src/main/java/com/vividsolutions/jts/geomgraph/Quadrant.java deleted file mode 100644 index 30b8403a16..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/Quadrant.java +++ /dev/null @@ -1,160 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph; - -/** - * @version 1.7 - */ -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Utility functions for working with quadrants, which are numbered as follows: - *
                    - * 1 | 0
                    - * --+--
                    - * 2 | 3
                    - * 
                    - *
                    - * @version 1.7
                    - */
                    -public class Quadrant 
                    -{
                    -	public static final int NE = 0;
                    -	public static final int NW = 1;
                    -	public static final int SW = 2;
                    -	public static final int SE = 3;
                    -	
                    -  /**
                    -   * Returns the quadrant of a directed line segment (specified as x and y
                    -   * displacements, which cannot both be 0).
                    -   * 
                    -   * @throws IllegalArgumentException if the displacements are both 0
                    -   */
                    -  public static int quadrant(double dx, double dy)
                    -  {
                    -    if (dx == 0.0 && dy == 0.0)
                    -      throw new IllegalArgumentException("Cannot compute the quadrant for point ( "+ dx + ", " + dy + " )" );
                    -    if (dx >= 0.0) {
                    -      if (dy >= 0.0)
                    -        return NE;
                    -      else
                    -        return SE;
                    -    }
                    -    else {
                    -    	if (dy >= 0.0)
                    -    		return NW;
                    -    	else
                    -    		return SW;
                    -    }
                    -  }
                    -
                    -  /**
                    -   * Returns the quadrant of a directed line segment from p0 to p1.
                    -   * 
                    -   * @throws IllegalArgumentException if the points are equal
                    -   */
                    -  public static int quadrant(Coordinate p0, Coordinate p1)
                    -  {
                    -    if (p1.x == p0.x && p1.y == p0.y)
                    -      throw new IllegalArgumentException("Cannot compute the quadrant for two identical points " + p0);
                    -    
                    -    if (p1.x >= p0.x) {
                    -      if (p1.y >= p0.y)
                    -        return NE;
                    -      else
                    -        return SE;
                    -    }
                    -    else {
                    -    	if (p1.y >= p0.y)
                    -    		return NW;
                    -    	else
                    -    		return SW;
                    -    }
                    -  }
                    -
                    -  /**
                    -   * Returns true if the quadrants are 1 and 3, or 2 and 4
                    -   */
                    -  public static boolean isOpposite(int quad1, int quad2)
                    -  {
                    -    if (quad1 == quad2) return false;
                    -    int diff = (quad1 - quad2 + 4) % 4;
                    -    // if quadrants are not adjacent, they are opposite
                    -    if (diff == 2) return true;
                    -    return false;
                    -  }
                    -
                    -  /** 
                    -   * Returns the right-hand quadrant of the halfplane defined by the two quadrants,
                    -   * or -1 if the quadrants are opposite, or the quadrant if they are identical.
                    -   */
                    -  public static int commonHalfPlane(int quad1, int quad2)
                    -  {
                    -    // if quadrants are the same they do not determine a unique common halfplane.
                    -    // Simply return one of the two possibilities
                    -    if (quad1 == quad2) return quad1;
                    -    int diff = (quad1 - quad2 + 4) % 4;
                    -    // if quadrants are not adjacent, they do not share a common halfplane
                    -    if (diff == 2) return -1;
                    -    //
                    -    int min = (quad1 < quad2) ? quad1 : quad2;
                    -    int max = (quad1 > quad2) ? quad1 : quad2;
                    -    // for this one case, the righthand plane is NOT the minimum index;
                    -    if (min == 0 && max == 3) return 3;
                    -    // in general, the halfplane index is the minimum of the two adjacent quadrants
                    -    return min;
                    -  }
                    -
                    -  /**
                    -   * Returns whether the given quadrant lies within the given halfplane (specified
                    -   * by its right-hand quadrant).
                    -   */
                    -  public static boolean isInHalfPlane(int quad, int halfPlane)
                    -  {
                    -    if (halfPlane == SE) {
                    -      return quad == SE || quad == SW;
                    -    }
                    -    return quad == halfPlane || quad == halfPlane + 1;
                    -  }
                    -    
                    -  /**
                    -   * Returns true if the given quadrant is 0 or 1.
                    -   */
                    -  public static boolean isNorthern(int quad)
                    -  {
                    -    return quad == NE || quad == NW;
                    -  }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/TopologyLocation.java b/src/main/java/com/vividsolutions/jts/geomgraph/TopologyLocation.java
                    deleted file mode 100644
                    index 9360aece46..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/geomgraph/TopologyLocation.java
                    +++ /dev/null
                    @@ -1,207 +0,0 @@
                    -
                    -
                    -
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.geomgraph;
                    -
                    -
                    -
                    -import com.vividsolutions.jts.geomgraph.Position;
                    -import com.vividsolutions.jts.geom.Location;
                    -
                    -/**
                    -  * A TopologyLocation is the labelling of a
                    -  * GraphComponent's topological relationship to a single Geometry.
                    -  * 

                    - * If the parent component is an area edge, each side and the edge itself - * have a topological location. These locations are named - *

                      - *
                    • ON: on the edge - *
                    • LEFT: left-hand side of the edge - *
                    • RIGHT: right-hand side - *
                    - * If the parent component is a line edge or node, there is a single - * topological relationship attribute, ON. - *

                    - * The possible values of a topological location are - * {Location.NONE, Location.EXTERIOR, Location.BOUNDARY, Location.INTERIOR} - *

                    - * The labelling is stored in an array location[j] where - * where j has the values ON, LEFT, RIGHT - * @version 1.7 - */ -public class TopologyLocation { - - int location[]; - - public TopologyLocation(int[] location) - { - init(location.length); - } - /** - * Constructs a TopologyLocation specifying how points on, to the left of, and to the - * right of some GraphComponent relate to some Geometry. Possible values for the - * parameters are Location.NULL, Location.EXTERIOR, Location.BOUNDARY, - * and Location.INTERIOR. - * @see Location - */ - public TopologyLocation(int on, int left, int right) { - init(3); - location[Position.ON] = on; - location[Position.LEFT] = left; - location[Position.RIGHT] = right; - } - - public TopologyLocation(int on) { - init(1); - location[Position.ON] = on; - } - public TopologyLocation(TopologyLocation gl) { - init(gl.location.length); - if (gl != null) { - for (int i = 0; i < location.length; i++) { - location[i] = gl.location[i]; - } - } - } - private void init(int size) - { - location = new int[size]; - setAllLocations(Location.NONE); - } - public int get(int posIndex) - { - if (posIndex < location.length) return location[posIndex]; - return Location.NONE; - } - /** - * @return true if all locations are NULL - */ - public boolean isNull() - { - for (int i = 0; i < location.length; i++) { - if (location[i] != Location.NONE) return false; - } - return true; - } - /** - * @return true if any locations are NULL - */ - public boolean isAnyNull() - { - for (int i = 0; i < location.length; i++) { - if (location[i] == Location.NONE) return true; - } - return false; - } - public boolean isEqualOnSide(TopologyLocation le, int locIndex) - { - return location[locIndex] == le.location[locIndex]; - } - public boolean isArea() { return location.length > 1; } - public boolean isLine() { return location.length == 1; } - - public void flip() - { - if (location.length <= 1) return; - int temp = location[Position.LEFT]; - location[Position.LEFT] = location[Position.RIGHT]; - location[Position.RIGHT] = temp; - } - - - public void setAllLocations(int locValue) - { - for (int i = 0; i < location.length; i++) { - location[i] = locValue; - } - } - public void setAllLocationsIfNull(int locValue) - { - for (int i = 0; i < location.length; i++) { - if (location[i] == Location.NONE) location[i] = locValue; - } - } - - public void setLocation(int locIndex, int locValue) - { - location[locIndex] = locValue; - } - public void setLocation(int locValue) - { - setLocation(Position.ON, locValue); - } - public int[] getLocations() { return location; } - public void setLocations(int on, int left, int right) { - location[Position.ON] = on; - location[Position.LEFT] = left; - location[Position.RIGHT] = right; - } - public boolean allPositionsEqual(int loc) - { - for (int i = 0; i < location.length; i++) { - if (location[i] != loc) return false; - } - return true; - } - - /** - * merge updates only the NULL attributes of this object - * with the attributes of another. - */ - public void merge(TopologyLocation gl) - { - // if the src is an Area label & and the dest is not, increase the dest to be an Area - if (gl.location.length > location.length) { - int [] newLoc = new int[3]; - newLoc[Position.ON] = location[Position.ON]; - newLoc[Position.LEFT] = Location.NONE; - newLoc[Position.RIGHT] = Location.NONE; - location = newLoc; - } - for (int i = 0; i < location.length; i++) { - if (location[i] == Location.NONE && i < gl.location.length) - location[i] = gl.location[i]; - } - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - if (location.length > 1) buf.append(Location.toLocationSymbol(location[Position.LEFT])); - buf.append(Location.toLocationSymbol(location[Position.ON])); - if (location.length > 1) buf.append(Location.toLocationSymbol(location[Position.RIGHT])); - return buf.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java deleted file mode 100644 index e5ebc4314c..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java +++ /dev/null @@ -1,79 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * An EdgeSetIntersector computes all the intersections between the - * edges in the set. It adds the computed intersections to each edge - * they are found on. It may be used in two scenarios: - *

                      - *
                    • determining the internal intersections between a single set of edges - *
                    • determining the mutual intersections between two different sets of edges - *
                    - * It uses a {@link SegmentIntersector} to compute the intersections between - * segments and to record statistics about what kinds of intersections were found. - * - * @version 1.7 - */ -public abstract class EdgeSetIntersector -{ - public EdgeSetIntersector() { - } - - /** - * Computes all self-intersections between edges in a set of edges, - * allowing client to choose whether self-intersections are computed. - * - * @param edges a list of edges to test for intersections - * @param si the SegmentIntersector to use - * @param testAllSegments true if self-intersections are to be tested as well - */ - abstract public void computeIntersections(List edges, SegmentIntersector si, boolean testAllSegments); - - /** - * Computes all mutual intersections between two sets of edges. - */ - abstract public void computeIntersections(List edges0, List edges1, SegmentIntersector si); - - - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java deleted file mode 100644 index 07aef8fa4a..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java +++ /dev/null @@ -1,55 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -/** - * @version 1.7 - */ -public class MonotoneChain { - - MonotoneChainEdge mce; - int chainIndex; - - public MonotoneChain(MonotoneChainEdge mce, int chainIndex) { - this.mce = mce; - this.chainIndex = chainIndex; - } - - public void computeIntersections(MonotoneChain mc, SegmentIntersector si) - { - this.mce.computeIntersectsForChain(chainIndex, mc.mce, mc.chainIndex, si); - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java deleted file mode 100644 index 522dbd2bc5..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java +++ /dev/null @@ -1,154 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -import java.util.*; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.Debug; - -/** - * MonotoneChains are a way of partitioning the segments of an edge to - * allow for fast searching of intersections. - * They have the following properties: - *
                      - *
                    1. the segments within a monotone chain will never intersect each other - *
                    2. the envelope of any contiguous subset of the segments in a monotone chain - * is simply the envelope of the endpoints of the subset. - *
                    - * Property 1 means that there is no need to test pairs of segments from within - * the same monotone chain for intersection. - * Property 2 allows - * binary search to be used to find the intersection points of two monotone chains. - * For many types of real-world data, these properties eliminate a large number of - * segment comparisons, producing substantial speed gains. - * @version 1.7 - */ -public class MonotoneChainEdge { - - Edge e; - Coordinate[] pts; // cache a reference to the coord array, for efficiency - // the lists of start/end indexes of the monotone chains. - // Includes the end point of the edge as a sentinel - int[] startIndex; - // these envelopes are created once and reused - Envelope env1 = new Envelope(); - Envelope env2 = new Envelope(); - - public MonotoneChainEdge(Edge e) { - this.e = e; - pts = e.getCoordinates(); - MonotoneChainIndexer mcb = new MonotoneChainIndexer(); - startIndex = mcb.getChainStartIndices(pts); - } - - public Coordinate[] getCoordinates() { return pts; } - public int[] getStartIndexes() { return startIndex; } - - public double getMinX(int chainIndex) - { - double x1 = pts[startIndex[chainIndex]].x; - double x2 = pts[startIndex[chainIndex + 1]].x; - return x1 < x2 ? x1 : x2; - } - public double getMaxX(int chainIndex) - { - double x1 = pts[startIndex[chainIndex]].x; - double x2 = pts[startIndex[chainIndex + 1]].x; - return x1 > x2 ? x1 : x2; - } - - public void computeIntersects(MonotoneChainEdge mce, SegmentIntersector si) - { - for (int i = 0; i < startIndex.length - 1; i++) { - for (int j = 0; j < mce.startIndex.length - 1; j++) { - computeIntersectsForChain( i, - mce, j, - si ); - } - } - } - public void computeIntersectsForChain( - int chainIndex0, - MonotoneChainEdge mce, - int chainIndex1, - SegmentIntersector si) - { - computeIntersectsForChain(startIndex[chainIndex0], startIndex[chainIndex0 + 1], - mce, - mce.startIndex[chainIndex1], mce.startIndex[chainIndex1 + 1], - si ); - } - - private void computeIntersectsForChain( - int start0, int end0, - MonotoneChainEdge mce, - int start1, int end1, - SegmentIntersector ei) - { - Coordinate p00 = pts[start0]; - Coordinate p01 = pts[end0]; - Coordinate p10 = mce.pts[start1]; - Coordinate p11 = mce.pts[end1]; -//Debug.println("computeIntersectsForChain:" + p00 + p01 + p10 + p11); - // terminating condition for the recursion - if (end0 - start0 == 1 && end1 - start1 == 1) { - ei.addIntersections(e, start0, mce.e, start1); - return; - } - // nothing to do if the envelopes of these chains don't overlap - env1.init(p00, p01); - env2.init(p10, p11); - if (! env1.intersects(env2)) return; - - // the chains overlap, so split each in half and iterate (binary search) - int mid0 = (start0 + end0) / 2; - int mid1 = (start1 + end1) / 2; - - // Assert: mid != start or end (since we checked above for end - start <= 1) - // check terminating conditions before recursing - if (start0 < mid0) { - if (start1 < mid1) computeIntersectsForChain(start0, mid0, mce, start1, mid1, ei); - if (mid1 < end1) computeIntersectsForChain(start0, mid0, mce, mid1, end1, ei); - } - if (mid0 < end0) { - if (start1 < mid1) computeIntersectsForChain(mid0, end0, mce, start1, mid1, ei); - if (mid1 < end1) computeIntersectsForChain(mid0, end0, mce, mid1, end1, ei); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java deleted file mode 100644 index af7a767a5e..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java +++ /dev/null @@ -1,118 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -import java.util.*; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.Quadrant; - -/** - * MonotoneChains are a way of partitioning the segments of an edge to - * allow for fast searching of intersections. - * Specifically, a sequence of contiguous line segments - * is a monotone chain iff all the vectors defined by the oriented segments - * lies in the same quadrant. - *

                    - * Monotone Chains have the following useful properties: - *

                      - *
                    1. the segments within a monotone chain will never intersect each other - *
                    2. the envelope of any contiguous subset of the segments in a monotone chain - * is simply the envelope of the endpoints of the subset. - *
                    - * Property 1 means that there is no need to test pairs of segments from within - * the same monotone chain for intersection. - * Property 2 allows - * binary search to be used to find the intersection points of two monotone chains. - * For many types of real-world data, these properties eliminate a large number of - * segment comparisons, producing substantial speed gains. - *

                    - * Note that due to the efficient intersection test, there is no need to limit the size - * of chains to obtain fast performance. - * - * @version 1.7 - */ -public class MonotoneChainIndexer { - - public static int[] toIntArray(List list) - { - int[] array = new int[list.size()]; - for (int i = 0; i < array.length; i++) { - array[i] = ((Integer) list.get(i)).intValue(); - } - return array; - } - - public MonotoneChainIndexer() { - } - - public int[] getChainStartIndices(Coordinate[] pts) - { - // find the startpoint (and endpoints) of all monotone chains in this edge - int start = 0; - List startIndexList = new ArrayList(); - startIndexList.add(new Integer(start)); - do { - int last = findChainEnd(pts, start); - startIndexList.add(new Integer(last)); - start = last; - } while (start < pts.length - 1); - // copy list to an array of ints, for efficiency - int[] startIndex = toIntArray(startIndexList); - return startIndex; - } - - /** - * @return the index of the last point in the monotone chain - */ - private int findChainEnd(Coordinate[] pts, int start) - { - // determine quadrant for chain - int chainQuad = Quadrant.quadrant(pts[start], pts[start + 1]); - int last = start + 1; - while (last < pts.length ) { - //if (last - start > 100) break; - // compute quadrant for next possible segment in chain - int quad = Quadrant.quadrant(pts[last - 1], pts[last]); - if (quad != chainQuad) break; - last++; - } - return last - 1; - } - - - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java deleted file mode 100644 index ecce0b73d8..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java +++ /dev/null @@ -1,216 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.util.Debug; - - -/** - * Computes the intersection of line segments, - * and adds the intersection to the edges containing the segments. - * - * @version 1.7 - */ -public class SegmentIntersector -{ - - public static boolean isAdjacentSegments(int i1, int i2) - { - return Math.abs(i1 - i2) == 1; - } - - /** - * These variables keep track of what types of intersections were - * found during ALL edges that have been intersected. - */ - private boolean hasIntersection = false; - private boolean hasProper = false; - private boolean hasProperInterior = false; - // the proper intersection point found - private Coordinate properIntersectionPoint = null; - - private LineIntersector li; - private boolean includeProper; - private boolean recordIsolated; - private boolean isSelfIntersection; - //private boolean intersectionFound; - private int numIntersections = 0; - - // testing only - public int numTests = 0; - - private Collection[] bdyNodes; -/* - public SegmentIntersector() - { - } -*/ - public SegmentIntersector(LineIntersector li, boolean includeProper, boolean recordIsolated) - { - this.li = li; - this.includeProper = includeProper; - this.recordIsolated = recordIsolated; - } - - public void setBoundaryNodes( Collection bdyNodes0, - Collection bdyNodes1) - { - bdyNodes = new Collection[2]; - bdyNodes[0] = bdyNodes0; - bdyNodes[1] = bdyNodes1; - } - - /** - * @return the proper intersection point, or null if none was found - */ - public Coordinate getProperIntersectionPoint() { return properIntersectionPoint; } - - public boolean hasIntersection() { return hasIntersection; } - /** - * A proper intersection is an intersection which is interior to at least two - * line segments. Note that a proper intersection is not necessarily - * in the interior of the entire Geometry, since another edge may have - * an endpoint equal to the intersection, which according to SFS semantics - * can result in the point being on the Boundary of the Geometry. - */ - public boolean hasProperIntersection() { return hasProper; } - /** - * A proper interior intersection is a proper intersection which is not - * contained in the set of boundary nodes set for this SegmentIntersector. - */ - public boolean hasProperInteriorIntersection() { return hasProperInterior; } - - - /** - * A trivial intersection is an apparent self-intersection which in fact - * is simply the point shared by adjacent line segments. - * Note that closed edges require a special check for the point shared by the beginning - * and end segments. - */ - private boolean isTrivialIntersection(Edge e0, int segIndex0, Edge e1, int segIndex1) - { - if (e0 == e1) { - if (li.getIntersectionNum() == 1) { - if (isAdjacentSegments(segIndex0, segIndex1)) - return true; - if (e0.isClosed()) { - int maxSegIndex = e0.getNumPoints() - 1; - if ( (segIndex0 == 0 && segIndex1 == maxSegIndex) - || (segIndex1 == 0 && segIndex0 == maxSegIndex) ) { - return true; - } - } - } - } - return false; - } - - /** - * This method is called by clients of the EdgeIntersector class to test for and add - * intersections for two segments of the edges being intersected. - * Note that clients (such as MonotoneChainEdges) may choose not to intersect - * certain pairs of segments for efficiency reasons. - */ - public void addIntersections( - Edge e0, int segIndex0, - Edge e1, int segIndex1 - ) - { - if (e0 == e1 && segIndex0 == segIndex1) return; -numTests++; - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); -//if (li.hasIntersection() && li.isProper()) Debug.println(li); - /** - * Always record any non-proper intersections. - * If includeProper is true, record any proper intersections as well. - */ - if (li.hasIntersection()) { - if (recordIsolated) { - e0.setIsolated(false); - e1.setIsolated(false); - } - //intersectionFound = true; - numIntersections++; - // if the segments are adjacent they have at least one trivial intersection, - // the shared endpoint. Don't bother adding it if it is the - // only intersection. - if (! isTrivialIntersection(e0, segIndex0, e1, segIndex1)) { - hasIntersection = true; - if (includeProper || ! li.isProper() ) { -//Debug.println(li); - e0.addIntersections(li, segIndex0, 0); - e1.addIntersections(li, segIndex1, 1); - } - if (li.isProper()) { - properIntersectionPoint = (Coordinate) li.getIntersection(0).clone(); - hasProper = true; - if (! isBoundaryPoint(li, bdyNodes)) - hasProperInterior = true; - } - //if (li.isCollinear()) - //hasCollinear = true; - } - } - } - - private boolean isBoundaryPoint(LineIntersector li, Collection[] bdyNodes) - { - if (bdyNodes == null) return false; - if (isBoundaryPoint(li, bdyNodes[0])) return true; - if (isBoundaryPoint(li, bdyNodes[1])) return true; - return false; - } - - private boolean isBoundaryPoint(LineIntersector li, Collection bdyNodes) - { - for (Iterator i = bdyNodes.iterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - Coordinate pt = node.getCoordinate(); - if (li.isIntersection(pt)) return true; - } - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java deleted file mode 100644 index f4521518f1..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java +++ /dev/null @@ -1,101 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Finds all intersections in one or two sets of edges, - * using the straightforward method of - * comparing all segments. - * This algorithm is too slow for production use, but is useful for testing purposes. - * @version 1.7 - */ -public class SimpleEdgeSetIntersector - extends EdgeSetIntersector -{ - // statistics information - int nOverlaps; - - public SimpleEdgeSetIntersector() { - } - - public void computeIntersections(List edges, SegmentIntersector si, boolean testAllSegments) - { - nOverlaps = 0; - - for (Iterator i0 = edges.iterator(); i0.hasNext(); ) { - Edge edge0 = (Edge) i0.next(); - for (Iterator i1 = edges.iterator(); i1.hasNext(); ) { - Edge edge1 = (Edge) i1.next(); - if (testAllSegments || edge0 != edge1) - computeIntersects(edge0, edge1, si); - } - } - } - - - public void computeIntersections(List edges0, List edges1, SegmentIntersector si) - { - nOverlaps = 0; - - for (Iterator i0 = edges0.iterator(); i0.hasNext(); ) { - Edge edge0 = (Edge) i0.next(); - for (Iterator i1 = edges1.iterator(); i1.hasNext(); ) { - Edge edge1 = (Edge) i1.next(); - computeIntersects(edge0, edge1, si); - } - } - } - - /** - * Performs a brute-force comparison of every segment in each Edge. - * This has n^2 performance, and is about 100 times slower than using - * monotone chains. - */ - private void computeIntersects(Edge e0, Edge e1, SegmentIntersector si) - { - Coordinate[] pts0 = e0.getCoordinates(); - Coordinate[] pts1 = e1.getCoordinates(); - for (int i0 = 0; i0 < pts0.length - 1; i0++) { - for (int i1 = 0; i1 < pts1.length - 1; i1++) { - si.addIntersections(e0, i0, e1, i1); - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java deleted file mode 100644 index 6132344075..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java +++ /dev/null @@ -1,165 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Finds all intersections in one or two sets of edges, - * using an x-axis sweepline algorithm in conjunction with Monotone Chains. - * While still O(n^2) in the worst case, this algorithm - * drastically improves the average-case time. - * The use of MonotoneChains as the items in the index - * seems to offer an improvement in performance over a sweep-line alone. - * - * @version 1.7 - */ -public class SimpleMCSweepLineIntersector - extends EdgeSetIntersector -{ - - List events = new ArrayList(); - // statistics information - int nOverlaps; - - /** - * A SimpleMCSweepLineIntersector creates monotone chains from the edges - * and compares them using a simple sweep-line along the x-axis. - */ - public SimpleMCSweepLineIntersector() { - } - - public void computeIntersections(List edges, SegmentIntersector si, boolean testAllSegments) - { - if (testAllSegments) - add(edges, null); - else - add(edges); - computeIntersections(si); - } - - public void computeIntersections(List edges0, List edges1, SegmentIntersector si) - { - add(edges0, edges0); - add(edges1, edges1); - computeIntersections(si); - } - - private void add(List edges) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge edge = (Edge) i.next(); - // edge is its own group - add(edge, edge); - } - } - private void add(List edges, Object edgeSet) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge edge = (Edge) i.next(); - add(edge, edgeSet); - } - } - - private void add(Edge edge, Object edgeSet) - { - MonotoneChainEdge mce = edge.getMonotoneChainEdge(); - int[] startIndex = mce.getStartIndexes(); - for (int i = 0; i < startIndex.length - 1; i++) { - MonotoneChain mc = new MonotoneChain(mce, i); - SweepLineEvent insertEvent = new SweepLineEvent(edgeSet, mce.getMinX(i), mc); - events.add(insertEvent); - events.add(new SweepLineEvent(mce.getMaxX(i), insertEvent)); - } - } - - /** - * Because Delete Events have a link to their corresponding Insert event, - * it is possible to compute exactly the range of events which must be - * compared to a given Insert event object. - */ - private void prepareEvents() - { - Collections.sort(events); - // set DELETE event indexes - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isDelete()) { - ev.getInsertEvent().setDeleteEventIndex(i); - } - } - } - - private void computeIntersections(SegmentIntersector si) - { - nOverlaps = 0; - prepareEvents(); - - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isInsert()) { - processOverlaps(i, ev.getDeleteEventIndex(), ev, si); - } - } - } - - private void processOverlaps(int start, int end, SweepLineEvent ev0, SegmentIntersector si) - { - MonotoneChain mc0 = (MonotoneChain) ev0.getObject(); - /** - * Since we might need to test for self-intersections, - * include current INSERT event object in list of event objects to test. - * Last index can be skipped, because it must be a Delete event. - */ - for (int i = start; i < end; i++ ) { - SweepLineEvent ev1 = (SweepLineEvent) events.get(i); - if (ev1.isInsert()) { - MonotoneChain mc1 = (MonotoneChain) ev1.getObject(); - // don't compare edges in same group, if labels are present - if (! ev0.isSameLabel(ev1)) { - mc0.computeIntersections(mc1, si); - nOverlaps++; - } - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java deleted file mode 100644 index ad70ddef3d..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java +++ /dev/null @@ -1,161 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Finds all intersections in one or two sets of edges, - * using a simple x-axis sweepline algorithm. - * While still O(n^2) in the worst case, this algorithm - * drastically improves the average-case time. - * - * @version 1.7 - */ -public class SimpleSweepLineIntersector - extends EdgeSetIntersector -{ - - List events = new ArrayList(); - // statistics information - int nOverlaps; - - public SimpleSweepLineIntersector() { - } - - public void computeIntersections(List edges, SegmentIntersector si, boolean testAllSegments) - { - if (testAllSegments) - add(edges, null); - else - add(edges); - computeIntersections(si); - } - - public void computeIntersections(List edges0, List edges1, SegmentIntersector si) - { - add(edges0, edges0); - add(edges1, edges1); - computeIntersections(si); - } - - private void add(List edges) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge edge = (Edge) i.next(); - // edge is its own group - add(edge, edge); - } - } - private void add(List edges, Object edgeSet) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge edge = (Edge) i.next(); - add(edge, edgeSet); - } - } - - - private void add(Edge edge, Object edgeSet) - { - Coordinate[] pts = edge.getCoordinates(); - for (int i = 0; i < pts.length - 1; i++) { - SweepLineSegment ss = new SweepLineSegment(edge, i); - SweepLineEvent insertEvent = new SweepLineEvent(edgeSet, ss.getMinX(), null); - events.add(insertEvent); - events.add(new SweepLineEvent(ss.getMaxX(), insertEvent)); - } - } - - /** - * Because DELETE events have a link to their corresponding INSERT event, - * it is possible to compute exactly the range of events which must be - * compared to a given INSERT event object. - */ - private void prepareEvents() - { - Collections.sort(events); - // set DELETE event indexes - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isDelete()) { - ev.getInsertEvent().setDeleteEventIndex(i); - } - } - } - - private void computeIntersections(SegmentIntersector si) - { - nOverlaps = 0; - prepareEvents(); - - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isInsert()) { - processOverlaps(i, ev.getDeleteEventIndex(), ev, si); - } - } - } - - private void processOverlaps(int start, int end, SweepLineEvent ev0, SegmentIntersector si) - { - SweepLineSegment ss0 = (SweepLineSegment) ev0.getObject(); - /** - * Since we might need to test for self-intersections, - * include current INSERT event object in list of event objects to test. - * Last index can be skipped, because it must be a Delete event. - */ - for (int i = start; i < end; i++ ) { - SweepLineEvent ev1 = (SweepLineEvent) events.get(i); - if (ev1.isInsert()) { - SweepLineSegment ss1 = (SweepLineSegment) ev1.getObject(); - // don't compare edges in same group, if labels are present - if (! ev0.isSameLabel(ev1)) { - ss0.computeIntersections(ss1, si); - nOverlaps++; - } - } - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java deleted file mode 100644 index 24238568ef..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java +++ /dev/null @@ -1,112 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -/** - * @version 1.7 - */ -public class SweepLineEvent - implements Comparable -{ - private static final int INSERT = 1; - private static final int DELETE = 2; - - private Object label; // used for red-blue intersection detection - private double xValue; - private int eventType; - private SweepLineEvent insertEvent = null; // null if this is an INSERT event - private int deleteEventIndex; - private Object obj; - - /** - * Creates an INSERT event. - * - * @param label the edge set label for this object - * @param x the event location - * @param obj the object being inserted - */ - public SweepLineEvent(Object label, double x, Object obj) - { - this.eventType = INSERT; - this.label = label; - xValue = x; - this.obj = obj; - } - - /** - * Creates a DELETE event. - * - * @param x the event location - * @param insertEvent the corresponding INSERT event - */ - public SweepLineEvent(double x, SweepLineEvent insertEvent) - { - eventType = DELETE; - xValue = x; - this.insertEvent = insertEvent; - } - - public boolean isInsert() { return eventType == INSERT; } - public boolean isDelete() { return eventType == DELETE; } - public SweepLineEvent getInsertEvent() { return insertEvent; } - public int getDeleteEventIndex() { return deleteEventIndex; } - public void setDeleteEventIndex(int deleteEventIndex) { this.deleteEventIndex = deleteEventIndex; } - - public Object getObject() { return obj; } - - public boolean isSameLabel(SweepLineEvent ev) - { - // no label set indicates single group - if (label == null) return false; - return label == ev.label; - } - /** - * Events are ordered first by their x-value, and then by their eventType. - * Insert events are sorted before Delete events, so that - * items whose Insert and Delete events occur at the same x-value will be - * correctly handled. - */ - public int compareTo(Object o) { - SweepLineEvent pe = (SweepLineEvent) o; - if (xValue < pe.xValue) return -1; - if (xValue > pe.xValue) return 1; - if (eventType < pe.eventType) return -1; - if (eventType > pe.eventType) return 1; - return 0; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java b/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java deleted file mode 100644 index 7c32897817..0000000000 --- a/src/main/java/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java +++ /dev/null @@ -1,74 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.geomgraph.index; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.*; - - -/** - * @version 1.7 - */ -public class SweepLineSegment { - - Edge edge; - Coordinate[] pts; - int ptIndex; - - public SweepLineSegment(Edge edge, int ptIndex) { - this.edge = edge; - this.ptIndex = ptIndex; - pts = edge.getCoordinates(); - } - - public double getMinX() - { - double x1 = pts[ptIndex].x; - double x2 = pts[ptIndex + 1].x; - return x1 < x2 ? x1 : x2; - } - public double getMaxX() - { - double x1 = pts[ptIndex].x; - double x2 = pts[ptIndex + 1].x; - return x1 > x2 ? x1 : x2; - } - public void computeIntersections(SweepLineSegment ss, SegmentIntersector si) - { - si.addIntersections(edge, ptIndex, ss.edge, ss.ptIndex); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/ArrayListVisitor.java b/src/main/java/com/vividsolutions/jts/index/ArrayListVisitor.java deleted file mode 100644 index 29e2d38ff9..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/ArrayListVisitor.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.index; - -import java.util.*; -import com.vividsolutions.jts.index.ItemVisitor; - -/** - * @version 1.7 - */ -public class ArrayListVisitor - implements ItemVisitor -{ - - private ArrayList items = new ArrayList(); - public ArrayListVisitor() { - } - - public void visitItem(Object item) - { - items.add(item); - } - - public ArrayList getItems() { return items; } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/ItemVisitor.java b/src/main/java/com/vividsolutions/jts/index/ItemVisitor.java deleted file mode 100644 index 540224a204..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/ItemVisitor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.index; - -/** - * A visitor for items in an index. - * - * @version 1.7 - */ - -public interface ItemVisitor -{ - void visitItem(Object item); -} diff --git a/src/main/java/com/vividsolutions/jts/index/SpatialIndex.java b/src/main/java/com/vividsolutions/jts/index/SpatialIndex.java deleted file mode 100644 index 79d2a3f70f..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/SpatialIndex.java +++ /dev/null @@ -1,87 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index; - -import java.util.*; -import com.vividsolutions.jts.geom.Envelope; - -/** - * The basic operations supported by classes - * implementing spatial index algorithms. - *

                    - * A spatial index typically provides a primary filter for range rectangle queries. - * A secondary filter is required to test for exact intersection. - * The secondary filter may consist of other kinds of tests, - * such as testing other spatial relationships. - * - * @version 1.7 - */ -public interface SpatialIndex -{ - /** - * Adds a spatial item with an extent specified by the given {@link Envelope} to the index - */ - void insert(Envelope itemEnv, Object item); - - /** - * Queries the index for all items whose extents intersect the given search {@link Envelope} - * Note that some kinds of indexes may also return objects which do not in fact - * intersect the query envelope. - * - * @param searchEnv the envelope to query for - * @return a list of the items found by the query - */ - List query(Envelope searchEnv); - - /** - * Queries the index for all items whose extents intersect the given search {@link Envelope}, - * and applies an {@link ItemVisitor} to them. - * Note that some kinds of indexes may also return objects which do not in fact - * intersect the query envelope. - * - * @param searchEnv the envelope to query for - * @param visitor a visitor object to apply to the items found - */ - void query(Envelope searchEnv, ItemVisitor visitor); - - /** - * Removes a single item from the tree. - * - * @param itemEnv the Envelope of the item to remove - * @param item the item to remove - * @return true if the item was found - */ - boolean remove(Envelope itemEnv, Object item); - -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/Bintree.java b/src/main/java/com/vividsolutions/jts/index/bintree/Bintree.java deleted file mode 100644 index d01f3d2ad4..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/Bintree.java +++ /dev/null @@ -1,212 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Envelope; - -/** - * An BinTree (or "Binary Interval Tree") - * is a 1-dimensional version of a quadtree. - * It indexes 1-dimensional intervals (which may - * be the projection of 2-D objects on an axis). - * It supports range searching - * (where the range may be a single point). - * This structure is dynamic - - * new items can be added at any time, - * and it will support deletion of items - * (although this is not currently implemented). - *

                    - * This implementation does not require specifying the extent of the inserted - * items beforehand. It will automatically expand to accomodate any extent - * of dataset. - *

                    - * The bintree structure is used to provide a primary filter - * for interval queries. The query() method returns a list of - * all objects which may intersect the query interval. - * Note that it may return objects which do not in fact intersect. - * A secondary filter is required to test for exact intersection. - * Of course, this secondary filter may consist of other tests besides - * intersection, such as testing other kinds of spatial relationships. - *

                    - * This index is different to the Interval Tree of Edelsbrunner - * or the Segment Tree of Bentley. - * - * @version 1.7 - */ -public class Bintree -{ - /** - * Ensure that the Interval for the inserted item has non-zero extents. - * Use the current minExtent to pad it, if necessary - */ - public static Interval ensureExtent(Interval itemInterval, double minExtent) - { - double min = itemInterval.getMin(); - double max = itemInterval.getMax(); - // has a non-zero extent - if (min != max) return itemInterval; - - // pad extent - if (min == max) { - min = min - minExtent / 2.0; - max = min + minExtent / 2.0; - } - return new Interval(min, max); - } - - private Root root; - /** - * Statistics - * - * minExtent is the minimum extent of all items - * inserted into the tree so far. It is used as a heuristic value - * to construct non-zero extents for features with zero extent. - * Start with a non-zero extent, in case the first feature inserted has - * a zero extent in both directions. This value may be non-optimal, but - * only one feature will be inserted with this value. - **/ - private double minExtent = 1.0; - - public Bintree() - { - root = new Root(); - } - - public int depth() - { - if (root != null) return root.depth(); - return 0; - } - public int size() - { - if (root != null) return root.size(); - return 0; - } - /** - * Compute the total number of nodes in the tree - * - * @return the number of nodes in the tree - */ - public int nodeSize() - { - if (root != null) return root.nodeSize(); - return 0; - } - - public void insert(Interval itemInterval, Object item) - { - collectStats(itemInterval); - Interval insertInterval = ensureExtent(itemInterval, minExtent); -//int oldSize = size(); - root.insert(insertInterval, item); - /* DEBUG -int newSize = size(); -System.out.println("BinTree: size = " + newSize + " node size = " + nodeSize()); -if (newSize <= oldSize) { - System.out.println("Lost item!"); - root.insert(insertInterval, item); - System.out.println("reinsertion size = " + size()); -} - */ - } - - /** - * Removes a single item from the tree. - * - * @param itemEnv the Envelope of the item to be removed - * @param item the item to remove - * @return true if the item was found (and thus removed) - */ - public boolean remove(Interval itemInterval, Object item) - { - Interval insertInterval = ensureExtent(itemInterval, minExtent); - return root.remove(insertInterval, item); - } - - public Iterator iterator() - { - List foundItems = new ArrayList(); - root.addAllItems(foundItems); - return foundItems.iterator(); - } - - public List query(double x) - { - return query(new Interval(x, x)); - } - - /** - * Queries the tree to find all candidate items which - * may overlap the query interval. - * If the query interval is null, all items in the tree are found. - * - * min and max may be the same value - */ - public List query(Interval interval) - { - /** - * the items that are matched are all items in intervals - * which overlap the query interval - */ - List foundItems = new ArrayList(); - query(interval, foundItems); - return foundItems; - } - - /** - * Adds items in the tree which potentially overlap the query interval - * to the given collection. - * If the query interval is null, add all items in the tree. - * - * @param interval a query nterval, or null - * @param resultItems the candidate items found - */ - public void query(Interval interval, Collection foundItems) - { - root.addAllItemsFromOverlapping(interval, foundItems); - } - - private void collectStats(Interval interval) - { - double del = interval.getWidth(); - if (del < minExtent && del > 0.0) - minExtent = del; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/Interval.java b/src/main/java/com/vividsolutions/jts/index/bintree/Interval.java deleted file mode 100644 index 1ee20902de..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/Interval.java +++ /dev/null @@ -1,105 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - -/** - * Represents an (1-dimensional) closed interval on the Real number line. - * - * @version 1.7 - */ -public class Interval { - - public double min, max; - - public Interval() - { - min = 0.0; - max = 0.0; - } - - public Interval(double min, double max) - { - init(min, max); - } - public Interval(Interval interval) - { - init(interval.min, interval.max); - } - public void init(double min, double max) - { - this.min = min; - this.max = max; - if (min > max) { - this.min = max; - this.max = min; - } - } - public double getMin() { return min; } - public double getMax() { return max; } - public double getWidth() { return max - min; } - - public void expandToInclude(Interval interval) - { - if (interval.max > max) max = interval.max; - if (interval.min < min) min = interval.min; - } - public boolean overlaps(Interval interval) - { - return overlaps(interval.min, interval.max); - } - - public boolean overlaps(double min, double max) - { - if (this.min > max || this.max < min) return false; - return true; - } - - public boolean contains(Interval interval) - { - return contains(interval.min, interval.max); - } - public boolean contains(double min, double max) - { - return (min >= this.min && max <= this.max); - } - public boolean contains(double p) - { - return (p >= this.min && p <= this.max); - } - - public String toString() - { - return "[" + min + ", " + max + "]"; - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/Key.java b/src/main/java/com/vividsolutions/jts/index/bintree/Key.java deleted file mode 100644 index f8e528f6c9..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/Key.java +++ /dev/null @@ -1,96 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - - - -import com.vividsolutions.jts.index.quadtree.DoubleBits; - -/** - * A Key is a unique identifier for a node in a tree. - * It contains a lower-left point and a level number. The level number - * is the power of two for the size of the node envelope - * - * @version 1.7 - */ -public class Key { - - public static int computeLevel(Interval interval) - { - double dx = interval.getWidth(); - //int level = BinaryPower.exponent(dx) + 1; - int level = DoubleBits.exponent(dx) + 1; - return level; - } - - - // the fields which make up the key - private double pt = 0.0; - private int level = 0; - // auxiliary data which is derived from the key for use in computation - private Interval interval; - - public Key(Interval interval) - { - computeKey(interval); - } - - public double getPoint() { return pt; } - public int getLevel() { return level; } - public Interval getInterval() { return interval; } - - /** - * return a square envelope containing the argument envelope, - * whose extent is a power of two and which is based at a power of 2 - */ - public void computeKey(Interval itemInterval) - { - level = computeLevel(itemInterval); - interval = new Interval(); - computeInterval(level, itemInterval); - // MD - would be nice to have a non-iterative form of this algorithm - while (! interval.contains(itemInterval)) { - level += 1; - computeInterval(level, itemInterval); - } - } - - private void computeInterval(int level, Interval itemInterval) - { - double size = DoubleBits.powerOf2(level); - //double size = pow2.power(level); - pt = Math.floor(itemInterval.getMin() / size) * size; - interval.init(pt, pt + size); - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/Node.java b/src/main/java/com/vividsolutions/jts/index/bintree/Node.java deleted file mode 100644 index a18f5d8032..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/Node.java +++ /dev/null @@ -1,173 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - -import com.vividsolutions.jts.util.Assert; - -/** - * A node of a {@link Bintree}. - * - * @version 1.7 - */ -public class Node - extends NodeBase -{ - public static Node createNode(Interval itemInterval) - { - Key key = new Key(itemInterval); - -//System.out.println("input: " + env + " binaryEnv: " + key.getEnvelope()); - Node node = new Node(key.getInterval(), key.getLevel()); - return node; - } - - public static Node createExpanded(Node node, Interval addInterval) - { - Interval expandInt = new Interval(addInterval); - if (node != null) expandInt.expandToInclude(node.interval); - - Node largerNode = createNode(expandInt); - if (node != null) largerNode.insert(node); - return largerNode; - } - - private Interval interval; - private double centre; - private int level; - - public Node(Interval interval, int level) - { - this.interval = interval; - this.level = level; - centre = (interval.getMin() + interval.getMax()) / 2; - } - - public Interval getInterval() { return interval; } - - protected boolean isSearchMatch(Interval itemInterval) - { -// System.out.println(itemInterval + " overlaps " + interval + " : " -// + itemInterval.overlaps(interval)); - return itemInterval.overlaps(interval); - } - - /** - * Returns the subnode containing the envelope. - * Creates the node if - * it does not already exist. - */ - public Node getNode(Interval searchInterval) - { - int subnodeIndex = getSubnodeIndex(searchInterval, centre); - // if index is -1 searchEnv is not contained in a subnode - if (subnodeIndex != -1) { - // create the node if it does not exist - Node node = getSubnode(subnodeIndex); - // recursively search the found/created node - return node.getNode(searchInterval); - } - else { - return this; - } - } - - /** - * Returns the smallest existing - * node containing the envelope. - */ - public NodeBase find(Interval searchInterval) - { - int subnodeIndex = getSubnodeIndex(searchInterval, centre); - if (subnodeIndex == -1) - return this; - if (subnode[subnodeIndex] != null) { - // query lies in subnode, so search it - Node node = subnode[subnodeIndex]; - return node.find(searchInterval); - } - // no existing subnode, so return this one anyway - return this; - } - - void insert(Node node) - { - Assert.isTrue(interval == null || interval.contains(node.interval)); - int index = getSubnodeIndex(node.interval, centre); - if (node.level == level - 1) { - subnode[index] = node; - } - else { - // the node is not a direct child, so make a new child node to contain it - // and recursively insert the node - Node childNode = createSubnode(index); - childNode.insert(node); - subnode[index] = childNode; - } - } - - /** - * get the subnode for the index. - * If it doesn't exist, create it - */ - private Node getSubnode(int index) - { - if (subnode[index] == null) { - subnode[index] = createSubnode(index); - } - return subnode[index]; - } - - private Node createSubnode(int index) - { - // create a new subnode in the appropriate interval - - double min = 0.0; - double max = 0.0; - - switch (index) { - case 0: - min = interval.getMin(); - max = centre; - break; - case 1: - min = centre; - max = interval.getMax(); - break; - } - Interval subInt = new Interval(min, max); - Node node = new Node(subInt, level - 1); - return node; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/NodeBase.java b/src/main/java/com/vividsolutions/jts/index/bintree/NodeBase.java deleted file mode 100644 index a9dc887002..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/NodeBase.java +++ /dev/null @@ -1,195 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.vividsolutions.jts.geom.Envelope; - - -/** - * The base class for nodes in a {@link Bintree}. - * - * @version 1.7 - */ -public abstract class NodeBase { - - /** - * Returns the index of the subnode that wholely contains the given interval. - * If none does, returns -1. - */ - public static int getSubnodeIndex(Interval interval, double centre) - { - int subnodeIndex = -1; - if (interval.min >= centre) subnodeIndex = 1; - if (interval.max <= centre) subnodeIndex = 0; - return subnodeIndex; - } - - protected List items = new ArrayList(); - - /** - * subnodes are numbered as follows: - * - * 0 | 1 - */ - protected Node[] subnode = new Node[2]; - - public NodeBase() { - } - - public List getItems() { return items; } - - public void add(Object item) - { - items.add(item); - } - public List addAllItems(List items) - { - items.addAll(this.items); - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) { - subnode[i].addAllItems(items); - } - } - return items; - } - protected abstract boolean isSearchMatch(Interval interval); - - /** - * Adds items in the tree which potentially overlap the query interval - * to the given collection. - * If the query interval is null, add all items in the tree. - * - * @param interval a query nterval, or null - * @param resultItems the candidate items found - */ - public void addAllItemsFromOverlapping(Interval interval, Collection resultItems) - { - if (interval != null && ! isSearchMatch(interval)) - return; - - // some of these may not actually overlap - this is allowed by the bintree contract - resultItems.addAll(items); - - if (subnode[0] != null) subnode[0].addAllItemsFromOverlapping(interval, resultItems); - if (subnode[1] != null) subnode[1].addAllItemsFromOverlapping(interval, resultItems); - } - - /** - * Removes a single item from this subtree. - * - * @param itemInterval the envelope containing the item - * @param item the item to remove - * @return true if the item was found and removed - */ - public boolean remove(Interval itemInterval, Object item) - { - // use interval to restrict nodes scanned - if (! isSearchMatch(itemInterval)) - return false; - - boolean found = false; - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) { - found = subnode[i].remove(itemInterval, item); - if (found) { - // trim subtree if empty - if (subnode[i].isPrunable()) - subnode[i] = null; - break; - } - } - } - // if item was found lower down, don't need to search for it here - if (found) return found; - // otherwise, try and remove the item from the list of items in this node - found = items.remove(item); - return found; - } - - public boolean isPrunable() - { - return ! (hasChildren() || hasItems()); - } - - public boolean hasChildren() - { - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) - return true; - } - return false; - } - - public boolean hasItems() { return ! items.isEmpty(); } - - int depth() - { - int maxSubDepth = 0; - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) { - int sqd = subnode[i].depth(); - if (sqd > maxSubDepth) - maxSubDepth = sqd; - } - } - return maxSubDepth + 1; - } - - int size() - { - int subSize = 0; - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) { - subSize += subnode[i].size(); - } - } - return subSize + items.size(); - } - - int nodeSize() - { - int subSize = 0; - for (int i = 0; i < 2; i++) { - if (subnode[i] != null) { - subSize += subnode[i].nodeSize(); - } - } - return subSize + 1; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/bintree/Root.java b/src/main/java/com/vividsolutions/jts/index/bintree/Root.java deleted file mode 100644 index 88cbbbfb55..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/bintree/Root.java +++ /dev/null @@ -1,121 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.bintree; - -import com.vividsolutions.jts.index.quadtree.IntervalSize; -import com.vividsolutions.jts.util.Assert; - -/** - * The root node of a single {@link Bintree}. - * It is centred at the origin, - * and does not have a defined extent. - * - * @version 1.7 - */ -public class Root - extends NodeBase -{ - - // the singleton root node is centred at the origin. - private static final double origin = 0.0; - - public Root() - { - } - - /** - * Insert an item into the tree this is the root of. - */ - public void insert(Interval itemInterval, Object item) - { - int index = getSubnodeIndex(itemInterval, origin); - // if index is -1, itemEnv must contain the origin. - if (index == -1) { - add(item); - return; - } - /** - * the item must be contained in one interval, so insert it into the - * tree for that interval (which may not yet exist) - */ - Node node = subnode[index]; - /** - * If the subnode doesn't exist or this item is not contained in it, - * have to expand the tree upward to contain the item. - */ - - if (node == null || ! node.getInterval().contains(itemInterval)) { - Node largerNode = Node.createExpanded(node, itemInterval); - subnode[index] = largerNode; - } - /** - * At this point we have a subnode which exists and must contain - * contains the env for the item. Insert the item into the tree. - */ - insertContained(subnode[index], itemInterval, item); -//System.out.println("depth = " + root.depth() + " size = " + root.size()); - } - - /** - * insert an item which is known to be contained in the tree rooted at - * the given Node. Lower levels of the tree will be created - * if necessary to hold the item. - */ - private void insertContained(Node tree, Interval itemInterval, Object item) - { - Assert.isTrue(tree.getInterval().contains(itemInterval)); - /** - * Do NOT create a new node for zero-area intervals - this would lead - * to infinite recursion. Instead, use a heuristic of simply returning - * the smallest existing node containing the query - */ - boolean isZeroArea = IntervalSize.isZeroWidth(itemInterval.getMin(), itemInterval.getMax()); - NodeBase node; - if (isZeroArea) - node = tree.find(itemInterval); - else - node = tree.getNode(itemInterval); - node.add(item); - } - - /** - * The root node matches all searches - */ - protected boolean isSearchMatch(Interval interval) - { - return true; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChain.java b/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChain.java deleted file mode 100644 index 44b59a600a..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChain.java +++ /dev/null @@ -1,249 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.chain; - -import com.vividsolutions.jts.geom.*; - - -/** - * Monotone Chains are a way of partitioning the segments of a linestring to - * allow for fast searching of intersections. - * They have the following properties: - *

                      - *
                    1. the segments within a monotone chain never intersect each other - *
                    2. the envelope of any contiguous subset of the segments in a monotone chain - * is equal to the envelope of the endpoints of the subset. - *
                    - * Property 1 means that there is no need to test pairs of segments from within - * the same monotone chain for intersection. - *

                    - * Property 2 allows - * an efficient binary search to be used to find the intersection points of two monotone chains. - * For many types of real-world data, these properties eliminate a large number of - * segment comparisons, producing substantial speed gains. - *

                    - * One of the goals of this implementation of MonotoneChains is to be - * as space and time efficient as possible. One design choice that aids this - * is that a MonotoneChain is based on a subarray of a list of points. - * This means that new arrays of points (potentially very large) do not - * have to be allocated. - *

                    - * - * MonotoneChains support the following kinds of queries: - *

                      - *
                    • Envelope select: determine all the segments in the chain which - * intersect a given envelope - *
                    • Overlap: determine all the pairs of segments in two chains whose - * envelopes overlap - *
                    - * - * This implementation of MonotoneChains uses the concept of internal iterators - * ({@link MonotoneChainSelectAction} and {@link MonotoneChainOverlapAction}) - * to return the results for queries. - * This has time and space advantages, since it - * is not necessary to build lists of instantiated objects to represent the segments - * returned by the query. - * Queries made in this manner are thread-safe. - * - * @version 1.7 - */ -public class MonotoneChain { - - private Coordinate[] pts; - private int start, end; - private Envelope env = null; - private Object context = null;// user-defined information - private int id;// useful for optimizing chain comparisons - - public MonotoneChain(Coordinate[] pts, int start, int end, Object context) - { - this.pts = pts; - this.start = start; - this.end = end; - this.context = context; - } - - public void setId(int id) { this.id = id; } - public int getId() { return id; } - - public Object getContext() { return context; } - - public Envelope getEnvelope() - { - if (env == null) { - Coordinate p0 = pts[start]; - Coordinate p1 = pts[end]; - env = new Envelope(p0, p1); - } - return env; - } - - public int getStartIndex() { return start; } - public int getEndIndex() { return end; } - - /** - * Gets the line segment starting at index - * - * @param index index of segment - * @param ls line segment to extract into - */ - public void getLineSegment(int index, LineSegment ls) - { - ls.p0 = pts[index]; - ls.p1 = pts[index + 1]; - } - /** - * Return the subsequence of coordinates forming this chain. - * Allocates a new array to hold the Coordinates - */ - public Coordinate[] getCoordinates() - { - Coordinate coord[] = new Coordinate[end - start + 1]; - int index = 0; - for (int i = start; i <= end; i++) { - coord[index++] = pts[i]; - } - return coord; - } - - /** - * Determine all the line segments in the chain whose envelopes overlap - * the searchEnvelope, and process them. - *

                    - * The monotone chain search algorithm attempts to optimize - * performance by not calling the select action on chain segments - * which it can determine are not in the search envelope. - * However, it *may* call the select action on segments - * which do not intersect the search envelope. - * This saves on the overhead of checking envelope intersection - * each time, since clients may be able to do this more efficiently. - * - * @param searchEnv the search envelope - * @param mcs the select action to execute on selected segments - */ - public void select(Envelope searchEnv, MonotoneChainSelectAction mcs) - { - computeSelect(searchEnv, start, end, mcs); - } - - private void computeSelect( - Envelope searchEnv, - int start0, int end0, - MonotoneChainSelectAction mcs ) - { - Coordinate p0 = pts[start0]; - Coordinate p1 = pts[end0]; - mcs.tempEnv1.init(p0, p1); - -//Debug.println("trying:" + p0 + p1 + " [ " + start0 + ", " + end0 + " ]"); - // terminating condition for the recursion - if (end0 - start0 == 1) { - //Debug.println("computeSelect:" + p0 + p1); - mcs.select(this, start0); - return; - } - // nothing to do if the envelopes don't overlap - if (! searchEnv.intersects(mcs.tempEnv1)) - return; - - // the chains overlap, so split each in half and iterate (binary search) - int mid = (start0 + end0) / 2; - - // Assert: mid != start or end (since we checked above for end - start <= 1) - // check terminating conditions before recursing - if (start0 < mid) { - computeSelect(searchEnv, start0, mid, mcs); - } - if (mid < end0) { - computeSelect(searchEnv, mid, end0, mcs); - } - } - - /** - * Determine all the line segments in two chains which may overlap, and process them. - *

                    - * The monotone chain search algorithm attempts to optimize - * performance by not calling the overlap action on chain segments - * which it can determine do not overlap. - * However, it *may* call the overlap action on segments - * which do not actually interact. - * This saves on the overhead of checking intersection - * each time, since clients may be able to do this more efficiently. - * - * @param searchEnv the search envelope - * @param mco the overlap action to execute on selected segments - */ - public void computeOverlaps(MonotoneChain mc, MonotoneChainOverlapAction mco) - { - computeOverlaps(start, end, mc, mc.start, mc.end, mco); - } - - private void computeOverlaps( - int start0, int end0, - MonotoneChain mc, - int start1, int end1, - MonotoneChainOverlapAction mco) - { - Coordinate p00 = pts[start0]; - Coordinate p01 = pts[end0]; - Coordinate p10 = mc.pts[start1]; - Coordinate p11 = mc.pts[end1]; -//Debug.println("computeIntersectsForChain:" + p00 + p01 + p10 + p11); - // terminating condition for the recursion - if (end0 - start0 == 1 && end1 - start1 == 1) { - mco.overlap(this, start0, mc, start1); - return; - } - // nothing to do if the envelopes of these chains don't overlap - mco.tempEnv1.init(p00, p01); - mco.tempEnv2.init(p10, p11); - if (! mco.tempEnv1.intersects(mco.tempEnv2)) return; - - // the chains overlap, so split each in half and iterate (binary search) - int mid0 = (start0 + end0) / 2; - int mid1 = (start1 + end1) / 2; - - // Assert: mid != start or end (since we checked above for end - start <= 1) - // check terminating conditions before recursing - if (start0 < mid0) { - if (start1 < mid1) computeOverlaps(start0, mid0, mc, start1, mid1, mco); - if (mid1 < end1) computeOverlaps(start0, mid0, mc, mid1, end1, mco); - } - if (mid0 < end0) { - if (start1 < mid1) computeOverlaps(mid0, end0, mc, start1, mid1, mco); - if (mid1 < end1) computeOverlaps(mid0, end0, mc, mid1, end1, mco); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java b/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java deleted file mode 100644 index 37dcf138d2..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java +++ /dev/null @@ -1,139 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.chain; - -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.Quadrant; - -/** - * Constructs {@link MonotoneChain}s - * for sequences of {@link Coordinate}s. - * - * @version 1.7 - */ -public class MonotoneChainBuilder { - - public static int[] toIntArray(List list) - { - int[] array = new int[list.size()]; - for (int i = 0; i < array.length; i++) { - array[i] = ((Integer) list.get(i)).intValue(); - } - return array; - } - - public static List getChains(Coordinate[] pts) - { - return getChains(pts, null); - } - - /** - * Return a list of the {@link MonotoneChain}s - * for the given list of coordinates. - */ - public static List getChains(Coordinate[] pts, Object context) - { - List mcList = new ArrayList(); - int[] startIndex = getChainStartIndices(pts); - for (int i = 0; i < startIndex.length - 1; i++) { - MonotoneChain mc = new MonotoneChain(pts, startIndex[i], startIndex[i + 1], context); - mcList.add(mc); - } - return mcList; - } - - /** - * Return an array containing lists of start/end indexes of the monotone chains - * for the given list of coordinates. - * The last entry in the array points to the end point of the point array, - * for use as a sentinel. - */ - public static int[] getChainStartIndices(Coordinate[] pts) - { - // find the startpoint (and endpoints) of all monotone chains in this edge - int start = 0; - List startIndexList = new ArrayList(); - startIndexList.add(new Integer(start)); - do { - int last = findChainEnd(pts, start); - startIndexList.add(new Integer(last)); - start = last; - } while (start < pts.length - 1); - // copy list to an array of ints, for efficiency - int[] startIndex = toIntArray(startIndexList); - return startIndex; - } - - /** - * Finds the index of the last point in a monotone chain - * starting at a given point. - * Any repeated points (0-length segments) will be included - * in the monotone chain returned. - * - * @return the index of the last point in the monotone chain - * starting at start. - */ - private static int findChainEnd(Coordinate[] pts, int start) - { - int safeStart = start; - // skip any zero-length segments at the start of the sequence - // (since they cannot be used to establish a quadrant) - while (safeStart < pts.length - 1 && pts[safeStart].equals2D(pts[safeStart + 1])) { - safeStart++; - } - // check if there are NO non-zero-length segments - if (safeStart >= pts.length - 1) { - return pts.length - 1; - } - // determine overall quadrant for chain (which is the starting quadrant) - int chainQuad = Quadrant.quadrant(pts[safeStart], pts[safeStart + 1]); - int last = start + 1; - while (last < pts.length) { - // skip zero-length segments, but include them in the chain - if (! pts[last - 1].equals2D(pts[last])) { - // compute quadrant for next possible segment in chain - int quad = Quadrant.quadrant(pts[last - 1], pts[last]); - if (quad != chainQuad) break; - } - last++; - } - return last - 1; - } - - - public MonotoneChainBuilder() { - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java b/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java deleted file mode 100644 index 15ab89359a..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java +++ /dev/null @@ -1,76 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.chain; - -import com.vividsolutions.jts.geom.*; - -/** - * The action for the internal iterator for performing - * overlap queries on a MonotoneChain - * - * @version 1.7 - */ -public class MonotoneChainOverlapAction -{ - // these envelopes are used during the MonotoneChain search process - Envelope tempEnv1 = new Envelope(); - Envelope tempEnv2 = new Envelope(); - - protected LineSegment overlapSeg1 = new LineSegment(); - protected LineSegment overlapSeg2 = new LineSegment(); - - /** - * This function can be overridden if the original chains are needed - * - * @param start1 the index of the start of the overlapping segment from mc1 - * @param start2 the index of the start of the overlapping segment from mc2 - */ - public void overlap(MonotoneChain mc1, int start1, MonotoneChain mc2, int start2) - { - mc1.getLineSegment(start1, overlapSeg1); - mc2.getLineSegment(start2, overlapSeg2); - overlap(overlapSeg1, overlapSeg2); - } - - /** - * This is a convenience function which can be overridden to obtain the actual - * line segments which overlap - * @param seg1 - * @param seg2 - */ - public void overlap(LineSegment seg1, LineSegment seg2) - { - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java b/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java deleted file mode 100644 index 5e6b712508..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java +++ /dev/null @@ -1,75 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.chain; - -import com.vividsolutions.jts.geom.*; -/** - * The action for the internal iterator for performing - * envelope select queries on a MonotoneChain - * - * @version 1.7 - */ -public class MonotoneChainSelectAction -{ - // these envelopes are used during the MonotoneChain search process - Envelope tempEnv1 = new Envelope(); - - LineSegment selectedSegment = new LineSegment(); - - /** - * This method is overridden - * to process a segment - * in the context of the parent chain. - * - * @param mc the parent chain - * @param startIndex the index of the start vertex of the segment being processed - */ - public void select(MonotoneChain mc, int startIndex) - { - mc.getLineSegment(startIndex, selectedSegment); - // call this routine in case select(segmenet) was overridden - select(selectedSegment); - } - - /** - * This is a convenience method which can be overridden to obtain the actual - * line segment which is selected. - * - * @param seg - */ - public void select(LineSegment seg) - { - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeBranchNode.java b/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeBranchNode.java deleted file mode 100644 index 9cc04501b4..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeBranchNode.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.intervalrtree; - -import com.vividsolutions.jts.index.*; - -public class IntervalRTreeBranchNode -extends IntervalRTreeNode -{ - private IntervalRTreeNode node1; - private IntervalRTreeNode node2; - - public IntervalRTreeBranchNode(IntervalRTreeNode n1, IntervalRTreeNode n2) - { - node1 = n1; - node2 = n2; - buildExtent(node1, node2); - } - - private void buildExtent(IntervalRTreeNode n1, IntervalRTreeNode n2) - { - min = Math.min(n1.min, n2.min); - max = Math.max(n1.max, n2.max); - } - - public void query(double queryMin, double queryMax, ItemVisitor visitor) - { - if (! intersects(queryMin, queryMax)) { -// System.out.println("Does NOT Overlap branch: " + this); - return; - } -// System.out.println("Overlaps branch: " + this); - if (node1 != null) node1.query(queryMin, queryMax, visitor); - if (node2 != null) node2.query(queryMin, queryMax, visitor); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeLeafNode.java b/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeLeafNode.java deleted file mode 100644 index b8e3222857..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeLeafNode.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.intervalrtree; - -import com.vividsolutions.jts.index.*; - -public class IntervalRTreeLeafNode -extends IntervalRTreeNode -{ - private Object item; - - public IntervalRTreeLeafNode(double min, double max, Object item) - { - this.min = min; - this.max = max; - this.item = item; - } - - public void query(double queryMin, double queryMax, ItemVisitor visitor) - { - if (! intersects(queryMin, queryMax)) - return; - - visitor.visitItem(item); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeNode.java b/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeNode.java deleted file mode 100644 index 24f1894212..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/intervalrtree/IntervalRTreeNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.intervalrtree; - -import java.util.Comparator; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.*; -import com.vividsolutions.jts.index.*; - -public abstract class IntervalRTreeNode -{ - protected double min = Double.POSITIVE_INFINITY; - protected double max = Double.NEGATIVE_INFINITY; - - public double getMin() { return min; } - public double getMax() { return max; } - - public abstract void query(double queryMin, double queryMax, ItemVisitor visitor); - - protected boolean intersects(double queryMin, double queryMax) - { - if (min > queryMax - || max < queryMin) - return false; - return true; - } - - public String toString() - { - return WKTWriter.toLineString(new Coordinate(min, 0), new Coordinate(max, 0)); - } - - public static class NodeComparator implements Comparator - { - public int compare(Object o1, Object o2) - { - IntervalRTreeNode n1 = (IntervalRTreeNode) o1; - IntervalRTreeNode n2 = (IntervalRTreeNode) o2; - double mid1 = (n1.min + n1.max) / 2; - double mid2 = (n2.min + n2.max) / 2; - if (mid1 < mid2) return -1; - if (mid1 > mid2) return 1; - return 0; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java b/src/main/java/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java deleted file mode 100644 index ee73f955a8..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.intervalrtree; - -import java.util.*; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.index.*; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * A static index on a set of 1-dimensional intervals, - * using an R-Tree packed based on the order of the interval midpoints. - * It supports range searching, - * where the range is an interval of the real line (which may be a single point). - * A common use is to index 1-dimensional intervals which - * are the projection of 2-D objects onto an axis of the coordinate system. - *

                    - * This index structure is static - * - items cannot be added or removed once the first query has been made. - * The advantage of this characteristic is that the index performance - * can be optimized based on a fixed set of items. - * - * @author Martin Davis - */ -public class SortedPackedIntervalRTree -{ - private List leaves = new ArrayList(); - private IntervalRTreeNode root = null; - - public SortedPackedIntervalRTree() - { - - } - - /** - * Adds an item to the index which is associated with the given interval - * - * @param min the lower bound of the item interval - * @param max the upper bound of the item interval - * @param item the item to insert - * - * @throws IllegalStateException if the index has already been queried - */ - public void insert(double min, double max, Object item) - { - if (root != null) - throw new IllegalStateException("Index cannot be added to once it has been queried"); - leaves.add(new IntervalRTreeLeafNode(min, max, item)); - } - - private void init() - { - if (root != null) return; - buildRoot(); - } - - private synchronized void buildRoot() - { - if (root != null) return; - root = buildTree(); - } - - private IntervalRTreeNode buildTree() - { - - // sort the leaf nodes - Collections.sort(leaves, new IntervalRTreeNode.NodeComparator()); - - // now group nodes into blocks of two and build tree up recursively - List src = leaves; - List temp = null; - List dest = new ArrayList(); - - while (true) { - buildLevel(src, dest); - if (dest.size() == 1) - return (IntervalRTreeNode) dest.get(0); - - temp = src; - src = dest; - dest = temp; - } - } - - private int level = 0; - - private void buildLevel(List src, List dest) - { - level++; - dest.clear(); - for (int i = 0; i < src.size(); i += 2) { - IntervalRTreeNode n1 = (IntervalRTreeNode) src.get(i); - IntervalRTreeNode n2 = (i + 1 < src.size()) - ? (IntervalRTreeNode) src.get(i) : null; - if (n2 == null) { - dest.add(n1); - } else { - IntervalRTreeNode node = new IntervalRTreeBranchNode( - (IntervalRTreeNode) src.get(i), - (IntervalRTreeNode) src.get(i + 1)); -// printNode(node); -// System.out.println(node); - dest.add(node); - } - } - } - - private void printNode(IntervalRTreeNode node) - { - System.out.println(WKTWriter.toLineString(new Coordinate(node.min, level), new Coordinate(node.max, level))); - } - - /** - * Search for intervals in the index which intersect the given closed interval - * and apply the visitor to them. - * - * @param min the lower bound of the query interval - * @param max the upper bound of the query interval - * @param visitor the visitor to pass any matched items to - */ - public void query(double min, double max, ItemVisitor visitor) - { - init(); - - root.query(min, max, visitor); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/kdtree/KdNode.java b/src/main/java/com/vividsolutions/jts/index/kdtree/KdNode.java deleted file mode 100644 index dff8f1f049..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/kdtree/KdNode.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.index.kdtree; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A node of a {@link KdTree}, which represents one or more points in the same location. - * - * @author dskea - */ -public class KdNode { - - private Coordinate p = null; - private Object data; - private KdNode left; - private KdNode right; - private int count; - - /** - * Creates a new KdNode. - * - * @param _x coordinate of point - * @param _y coordinate of point - * @param data a data objects to associate with this node - */ - public KdNode(double _x, double _y, Object data) { - p = new Coordinate(_x, _y); - left = null; - right = null; - count = 1; - this.data = data; - } - - /** - * Creates a new KdNode. - * - * @param p point location of new node - * @param data a data objects to associate with this node - */ - public KdNode(Coordinate p, Object data) { - this.p = new Coordinate(p); - left = null; - right = null; - count = 1; - this.data = data; - } - - /** - * Returns the X coordinate of the node - * - * @retrun X coordiante of the node - */ - public double getX() { - return p.x; - } - - /** - * Returns the Y coordinate of the node - * - * @return Y coordiante of the node - */ - public double getY() { - return p.y; - } - - /** - * Returns the location of this node - * - * @return p location of this node - */ - public Coordinate getCoordinate() { - return p; - } - - /** - * Gets the user data object associated with this node. - * @return - */ - public Object getData() { - return data; - } - - /** - * Returns the left node of the tree - * - * @return left node - */ - public KdNode getLeft() { - return left; - } - - /** - * Returns the right node of the tree - * - * @return right node - */ - public KdNode getRight() { - return right; - } - - // Increments counts of points at this location - void increment() { - count = count + 1; - } - - /** - * Returns the number of inserted points that are coincident at this location. - * - * @return number of inserted points that this node represents - */ - public int getCount() { - return count; - } - - /** - * Tests whether more than one point with this value have been inserted (up to the tolerance) - * - * @return true if more than one point have been inserted with this value - */ - public boolean isRepeated() { - return count > 1; - } - - // Sets left node value - void setLeft(KdNode _left) { - left = _left; - } - - // Sets right node value - void setRight(KdNode _right) { - right = _right; - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/kdtree/KdNodeVisitor.java b/src/main/java/com/vividsolutions/jts/index/kdtree/KdNodeVisitor.java deleted file mode 100644 index 989b3954dc..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/kdtree/KdNodeVisitor.java +++ /dev/null @@ -1,50 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.index.kdtree; - -/** - * A visitor for {@link KdNode}s in a {@link KdTree} index. - * - * @version 1.7 - */ - -public interface KdNodeVisitor -{ - /** - * Visits a node. - * - * @param node the node to visit - */ - void visit(KdNode node); -} diff --git a/src/main/java/com/vividsolutions/jts/index/kdtree/KdTree.java b/src/main/java/com/vividsolutions/jts/index/kdtree/KdTree.java deleted file mode 100644 index 04fcb973ff..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/kdtree/KdTree.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.index.kdtree; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateList; -import com.vividsolutions.jts.geom.Envelope; - -/** - * An implementation of a 2-D KD-Tree. KD-trees provide fast range searching on - * point data. - *

                    - * This implementation supports detecting and snapping points which are closer - * than a given distance tolerance. - * If the same point (up to tolerance) is inserted - * more than once, it is snapped to the existing node. - * In other words, if a point is inserted which lies within the tolerance of a node already in the index, - * it is snapped to that node. - * When a point is snapped to a node then a new node is not created but the count of the existing node - * is incremented. - * If more than one node in the tree is within tolerance of an inserted point, - * the closest and then lowest node is snapped to. - * - * @author David Skea - * @author Martin Davis - */ -public class KdTree { - - /** - * Converts a collection of {@link KdNode}s to an array of {@link Coordinate}s. - * - * @param kdnodes - * a collection of nodes - * @return an array of the coordinates represented by the nodes - */ - public static Coordinate[] toCoordinates(Collection kdnodes) { - return toCoordinates(kdnodes, false); - } - - /** - * Converts a collection of {@link KdNode}s - * to an array of {@link Coordinate}s, - * specifying whether repeated nodes should be represented - * by multiple coordinates. - * - * @param kdnodes a collection of nodes - * @param includeRepeated true if repeated nodes should - * be included multiple times - * @return an array of the coordinates represented by the nodes - */ - public static Coordinate[] toCoordinates(Collection kdnodes, boolean includeRepeated) { - CoordinateList coord = new CoordinateList(); - for (Iterator it = kdnodes.iterator(); it.hasNext();) { - KdNode node = (KdNode) it.next(); - int count = includeRepeated ? node.getCount() : 1; - for (int i = 0; i < count; i++) { - coord.add(node.getCoordinate(), true); - } - } - return coord.toCoordinateArray(); - } - - private KdNode root = null; - private long numberOfNodes; - private double tolerance; - - /** - * Creates a new instance of a KdTree with a snapping tolerance of 0.0. (I.e. - * distinct points will not be snapped) - */ - public KdTree() { - this(0.0); - } - - /** - * Creates a new instance of a KdTree, specifying a snapping distance - * tolerance. Points which lie closer than the tolerance to a point already in - * the tree will be treated as identical to the existing point. - * - * @param tolerance - * the tolerance distance for considering two points equal - */ - public KdTree(double tolerance) { - this.tolerance = tolerance; - } - - /** - * Tests whether the index contains any items. - * - * @return true if the index does not contain any items - */ - public boolean isEmpty() { - if (root == null) - return true; - return false; - } - - /** - * Inserts a new point in the kd-tree, with no data. - * - * @param p - * the point to insert - * @return the kdnode containing the point - */ - public KdNode insert(Coordinate p) { - return insert(p, null); - } - - /** - * Inserts a new point into the kd-tree. - * - * @param p - * the point to insert - * @param data - * a data item for the point - * @return returns a new KdNode if a new point is inserted, else an existing - * node is returned with its counter incremented. This can be checked - * by testing returnedNode.getCount() > 1. - */ - public KdNode insert(Coordinate p, Object data) { - if (root == null) { - root = new KdNode(p, data); - return root; - } - - /** - * Check if the point is already in the tree, up to tolerance. - * If tolerance is zero, this phase of the insertion can be skipped. - */ - if ( tolerance > 0 ) { - KdNode matchNode = findBestMatchNode(p); - if (matchNode != null) { - // point already in index - increment counter - matchNode.increment(); - return matchNode; - } - } - - return insertExact(p, data); - } - - /** - * Finds the node in the tree which is the best match for a point - * being inserted. - * The match is made deterministic by returning the lowest of any nodes which - * lie the same distance from the point. - * There may be no match if the point is not within the distance tolerance of any - * existing node. - * - * @param p the point being inserted - * @return the best matching node - * @return null if no match was found - */ - private KdNode findBestMatchNode(Coordinate p) { - BestMatchVisitor visitor = new BestMatchVisitor(p, tolerance); - query(visitor.queryEnvelope(), visitor); - return visitor.getNode(); - } - - static private class BestMatchVisitor implements KdNodeVisitor { - - private double tolerance; - private KdNode matchNode = null; - private double matchDist = 0.0; - private Coordinate p; - - public BestMatchVisitor(Coordinate p, double tolerance) { - this.p = p; - this.tolerance = tolerance; - } - - public Envelope queryEnvelope() { - Envelope queryEnv = new Envelope(p); - queryEnv.expandBy(tolerance); - return queryEnv; - } - - public KdNode getNode() { - return matchNode; - } - - @Override - public void visit(KdNode node) { - double dist = p.distance(node.getCoordinate()); - boolean isInTolerance = dist <= tolerance; - if (! isInTolerance) return; - boolean update = false; - if (matchNode == null - || dist < matchDist - // if distances are the same, record the lesser coordinate - || (matchNode != null && dist == matchDist - && node.getCoordinate().compareTo(matchNode.getCoordinate()) < 1)) - update = true; - - if (update) { - matchNode = node; - matchDist = dist; - } - } - } - - /** - * Inserts a point known to be beyond the distance tolerance of any existing node. - * The point is inserted at the bottom of the exact splitting path, - * so that tree shape is deterministic. - * - * @param p the point to insert - * @param data the data for the point - * @return the created node - */ - private KdNode insertExact(Coordinate p, Object data) { - KdNode currentNode = root; - KdNode leafNode = root; - boolean isOddLevel = true; - boolean isLessThan = true; - - /** - * Traverse the tree, first cutting the plane left-right (by X ordinate) - * then top-bottom (by Y ordinate) - */ - while (currentNode != null) { - // test if point is already a node (not strictly necessary) - if (currentNode != null) { - boolean isInTolerance = p.distance(currentNode.getCoordinate()) <= tolerance; - - // check if point is already in tree (up to tolerance) and if so simply - // return existing node - if (isInTolerance) { - currentNode.increment(); - return currentNode; - } - } - - if (isOddLevel) { - isLessThan = p.x < currentNode.getX(); - } else { - isLessThan = p.y < currentNode.getY(); - } - leafNode = currentNode; - if (isLessThan) { - currentNode = currentNode.getLeft(); - } else { - currentNode = currentNode.getRight(); - } - - isOddLevel = ! isOddLevel; - } - - // no node found, add new leaf node to tree - numberOfNodes = numberOfNodes + 1; - KdNode node = new KdNode(p, data); - if (isLessThan) { - leafNode.setLeft(node); - } else { - leafNode.setRight(node); - } - return node; - } - - private void queryNode(KdNode currentNode, - Envelope queryEnv, boolean odd, KdNodeVisitor visitor) { - if (currentNode == null) - return; - - double min; - double max; - double discriminant; - if (odd) { - min = queryEnv.getMinX(); - max = queryEnv.getMaxX(); - discriminant = currentNode.getX(); - } else { - min = queryEnv.getMinY(); - max = queryEnv.getMaxY(); - discriminant = currentNode.getY(); - } - boolean searchLeft = min < discriminant; - boolean searchRight = discriminant <= max; - - // search is computed via in-order traversal - if (searchLeft) { - queryNode(currentNode.getLeft(), queryEnv, !odd, visitor); - } - if (queryEnv.contains(currentNode.getCoordinate())) { - visitor.visit(currentNode); - } - if (searchRight) { - queryNode(currentNode.getRight(), queryEnv, !odd, visitor); - } - - } - - /** - * Performs a range search of the points in the index and visits all nodes found. - * - * @param queryEnv - * the range rectangle to query - * @param a visitor to visit all nodes found by the search - */ - public void query(Envelope queryEnv, KdNodeVisitor visitor) { - queryNode(root, queryEnv, true, visitor); - } - - /** - * Performs a range search of the points in the index. - * - * @param queryEnv - * the range rectangle to query - * @return a list of the KdNodes found - */ - public List query(Envelope queryEnv) { - final List result = new ArrayList(); - query(queryEnv, result); - return result; - } - - /** - * Performs a range search of the points in the index. - * - * @param queryEnv - * the range rectangle to query - * @param result - * a list to accumulate the result nodes into - */ - public void query(Envelope queryEnv, final List result) { - queryNode(root, queryEnv, true, new KdNodeVisitor() { - - @Override - public void visit(KdNode node) { - result.add(node); - } - - }); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/DoubleBits.java b/src/main/java/com/vividsolutions/jts/index/quadtree/DoubleBits.java deleted file mode 100644 index 4e2e9c8213..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/DoubleBits.java +++ /dev/null @@ -1,174 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -/** - * DoubleBits manipulates Double numbers - * by using bit manipulation and bit-field extraction. - * For some operations (such as determining the exponent) - * this is more accurate than using mathematical operations - * (which suffer from round-off error). - *

                    - * The algorithms and constants in this class - * apply only to IEEE-754 double-precision floating point format. - * - * @version 1.7 - */ -public class DoubleBits { - - public static final int EXPONENT_BIAS = 1023; - - public static double powerOf2(int exp) - { - if (exp > 1023 || exp < -1022) - throw new IllegalArgumentException("Exponent out of bounds"); - long expBias = exp + EXPONENT_BIAS; - long bits = (long) expBias << 52; - return Double.longBitsToDouble(bits); - } - - public static int exponent(double d) - { - DoubleBits db = new DoubleBits(d); - return db.getExponent(); - } - - public static double truncateToPowerOfTwo(double d) - { - DoubleBits db = new DoubleBits(d); - db.zeroLowerBits(52); - return db.getDouble(); - } - - public static String toBinaryString(double d) - { - DoubleBits db = new DoubleBits(d); - return db.toString(); - } - - public static double maximumCommonMantissa(double d1, double d2) - { - if (d1 == 0.0 || d2 == 0.0) return 0.0; - - DoubleBits db1 = new DoubleBits(d1); - DoubleBits db2 = new DoubleBits(d2); - - if (db1.getExponent() != db2.getExponent()) return 0.0; - - int maxCommon = db1.numCommonMantissaBits(db2); - db1.zeroLowerBits(64 - (12 + maxCommon)); - return db1.getDouble(); - } - - private double x; - private long xBits; - - public DoubleBits(double x) - { - this.x = x; - xBits = Double.doubleToLongBits(x); - } - - public double getDouble() - { - return Double.longBitsToDouble(xBits); - } - - /** - * Determines the exponent for the number - */ - public int biasedExponent() - { - int signExp = (int) (xBits >> 52); - int exp = signExp & 0x07ff; - return exp; - } - - /** - * Determines the exponent for the number - */ - public int getExponent() - { - return biasedExponent() - EXPONENT_BIAS; - } - - public void zeroLowerBits(int nBits) - { - long invMask = (1L << nBits) - 1L; - long mask = ~ invMask; - xBits &= mask; - } - - public int getBit(int i) - { - long mask = (1L << i); - return (xBits & mask) != 0 ? 1 : 0; - } - - /** - * This computes the number of common most-significant bits in the mantissa. - * It does not count the hidden bit, which is always 1. - * It does not determine whether the numbers have the same exponent - if they do - * not, the value computed by this function is meaningless. - * @param db - * @return the number of common most-significant mantissa bits - */ - public int numCommonMantissaBits(DoubleBits db) - { - for (int i = 0; i < 52; i++) - { - int bitIndex = i + 12; - if (getBit(i) != db.getBit(i)) - return i; - } - return 52; - } - - /** - * A representation of the Double bits formatted for easy readability - */ - public String toString() - { - String numStr = Long.toBinaryString(xBits); - // 64 zeroes! - String zero64 = "0000000000000000000000000000000000000000000000000000000000000000"; - String padStr = zero64 + numStr; - String bitStr = padStr.substring(padStr.length() - 64); - String str = bitStr.substring(0, 1) + " " - + bitStr.substring(1, 12) + "(" + getExponent() + ") " - + bitStr.substring(12) - + " [ " + x + " ]"; - return str; - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/IntervalSize.java b/src/main/java/com/vividsolutions/jts/index/quadtree/IntervalSize.java deleted file mode 100644 index 7dcf6250aa..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/IntervalSize.java +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -/** - * Provides a test for whether an interval is - * so small it should be considered as zero for the purposes of - * inserting it into a binary tree. - * The reason this check is necessary is that round-off error can - * cause the algorithm used to subdivide an interval to fail, by - * computing a midpoint value which does not lie strictly between the - * endpoints. - * - * @version 1.7 - */ -public class IntervalSize { - - /** - * This value is chosen to be a few powers of 2 less than the - * number of bits available in the double representation (i.e. 53). - * This should allow enough extra precision for simple computations to be correct, - * at least for comparison purposes. - */ - public static final int MIN_BINARY_EXPONENT = -50; - - /** - * Computes whether the interval [min, max] is effectively zero width. - * I.e. the width of the interval is so much less than the - * location of the interval that the midpoint of the interval cannot be - * represented precisely. - */ - public static boolean isZeroWidth(double min, double max) - { - double width = max - min; - if (width == 0.0) return true; - - double maxAbs = Math.max(Math.abs(min), Math.abs(max)); - double scaledInterval = width / maxAbs; - int level = DoubleBits.exponent(scaledInterval); - return level <= MIN_BINARY_EXPONENT; - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/Key.java b/src/main/java/com/vividsolutions/jts/index/quadtree/Key.java deleted file mode 100644 index 2928f096e2..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/Key.java +++ /dev/null @@ -1,102 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; - -/** - * A Key is a unique identifier for a node in a quadtree. - * It contains a lower-left point and a level number. The level number - * is the power of two for the size of the node envelope - * - * @version 1.7 - */ -public class Key { - - public static int computeQuadLevel(Envelope env) - { - double dx = env.getWidth(); - double dy = env.getHeight(); - double dMax = dx > dy ? dx : dy; - int level = DoubleBits.exponent(dMax) + 1; - return level; - } - - // the fields which make up the key - private Coordinate pt = new Coordinate(); - private int level = 0; - // auxiliary data which is derived from the key for use in computation - private Envelope env = null; - - public Key(Envelope itemEnv) - { - computeKey(itemEnv); - } - - public Coordinate getPoint() { return pt; } - public int getLevel() { return level; } - public Envelope getEnvelope() { return env; } - - public Coordinate getCentre() - { - return new Coordinate( - (env.getMinX() + env.getMaxX()) / 2, - (env.getMinY() + env.getMaxY()) / 2 - ); - } - /** - * return a square envelope containing the argument envelope, - * whose extent is a power of two and which is based at a power of 2 - */ - public void computeKey(Envelope itemEnv) - { - level = computeQuadLevel(itemEnv); - env = new Envelope(); - computeKey(level, itemEnv); - // MD - would be nice to have a non-iterative form of this algorithm - while (! env.contains(itemEnv)) { - level += 1; - computeKey(level, itemEnv); - } - } - - private void computeKey(int level, Envelope itemEnv) - { - double quadSize = DoubleBits.powerOf2(level); - pt.x = Math.floor(itemEnv.getMinX() / quadSize) * quadSize; - pt.y = Math.floor(itemEnv.getMinY() / quadSize) * quadSize; - env.init(pt.x, pt.x + quadSize, pt.y, pt.y + quadSize); - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/Node.java b/src/main/java/com/vividsolutions/jts/index/quadtree/Node.java deleted file mode 100644 index 345709462f..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/Node.java +++ /dev/null @@ -1,199 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.util.Assert; - -/** - * Represents a node of a {@link Quadtree}. Nodes contain - * items which have a spatial extent corresponding to the node's position - * in the quadtree. - * - * @version 1.7 - */ -public class Node - extends NodeBase -{ - public static Node createNode(Envelope env) - { - Key key = new Key(env); - Node node = new Node(key.getEnvelope(), key.getLevel()); - return node; - } - - public static Node createExpanded(Node node, Envelope addEnv) - { - Envelope expandEnv = new Envelope(addEnv); - if (node != null) expandEnv.expandToInclude(node.env); - - Node largerNode = createNode(expandEnv); - if (node != null) largerNode.insertNode(node); - return largerNode; - } - - private Envelope env; - private double centrex; - private double centrey; - private int level; - - public Node(Envelope env, int level) - { - //this.parent = parent; - this.env = env; - this.level = level; - centrex = (env.getMinX() + env.getMaxX()) / 2; - centrey = (env.getMinY() + env.getMaxY()) / 2; - } - - public Envelope getEnvelope() { return env; } - - protected boolean isSearchMatch(Envelope searchEnv) - { - return env.intersects(searchEnv); - } - - /** - * Returns the subquad containing the envelope searchEnv. - * Creates the subquad if - * it does not already exist. - * - * @return the subquad containing the search envelope - */ - public Node getNode(Envelope searchEnv) - { - int subnodeIndex = getSubnodeIndex(searchEnv, centrex, centrey); - // if subquadIndex is -1 searchEnv is not contained in a subquad - if (subnodeIndex != -1) { - // create the quad if it does not exist - Node node = getSubnode(subnodeIndex); - // recursively search the found/created quad - return node.getNode(searchEnv); - } - else { - return this; - } - } - - /** - * Returns the smallest existing - * node containing the envelope. - */ - public NodeBase find(Envelope searchEnv) - { - int subnodeIndex = getSubnodeIndex(searchEnv, centrex, centrey); - if (subnodeIndex == -1) - return this; - if (subnode[subnodeIndex] != null) { - // query lies in subquad, so search it - Node node = subnode[subnodeIndex]; - return node.find(searchEnv); - } - // no existing subquad, so return this one anyway - return this; - } - - void insertNode(Node node) - { - Assert.isTrue(env == null || env.contains(node.env)); -//System.out.println(env); -//System.out.println(quad.env); - int index = getSubnodeIndex(node.env, centrex, centrey); -//System.out.println(index); - if (node.level == level - 1) { - subnode[index] = node; -//System.out.println("inserted"); - } - else { - // the quad is not a direct child, so make a new child quad to contain it - // and recursively insert the quad - Node childNode = createSubnode(index); - childNode.insertNode(node); - subnode[index] = childNode; - } - } - - /** - * get the subquad for the index. - * If it doesn't exist, create it - */ - private Node getSubnode(int index) - { - if (subnode[index] == null) { - subnode[index] = createSubnode(index); - } - return subnode[index]; - } - - private Node createSubnode(int index) - { - // create a new subquad in the appropriate quadrant - - double minx = 0.0; - double maxx = 0.0; - double miny = 0.0; - double maxy = 0.0; - - switch (index) { - case 0: - minx = env.getMinX(); - maxx = centrex; - miny = env.getMinY(); - maxy = centrey; - break; - case 1: - minx = centrex; - maxx = env.getMaxX(); - miny = env.getMinY(); - maxy = centrey; - break; - case 2: - minx = env.getMinX(); - maxx = centrex; - miny = centrey; - maxy = env.getMaxY(); - break; - case 3: - minx = centrex; - maxx = env.getMaxX(); - miny = centrey; - maxy = env.getMaxY(); - break; - } - Envelope sqEnv = new Envelope(minx, maxx, miny, maxy); - Node node = new Node(sqEnv, level - 1); - return node; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/NodeBase.java b/src/main/java/com/vividsolutions/jts/index/quadtree/NodeBase.java deleted file mode 100644 index 25f382dced..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/NodeBase.java +++ /dev/null @@ -1,290 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.index.ItemVisitor; - -/** - * The base class for nodes in a {@link Quadtree}. - * - * @version 1.7 - */ -public abstract class NodeBase implements Serializable { - -//DEBUG private static int itemCount = 0; // debugging - - /** - * Gets the index of the subquad that wholly contains the given envelope. - * If none does, returns -1. - * - * @return the index of the subquad that wholly contains the given envelope - * or -1 if no subquad wholly contains the envelope - */ - public static int getSubnodeIndex(Envelope env, double centrex, double centrey) - { - int subnodeIndex = -1; - if (env.getMinX() >= centrex) { - if (env.getMinY() >= centrey) subnodeIndex = 3; - if (env.getMaxY() <= centrey) subnodeIndex = 1; - } - if (env.getMaxX() <= centrex) { - if (env.getMinY() >= centrey) subnodeIndex = 2; - if (env.getMaxY() <= centrey) subnodeIndex = 0; - } - return subnodeIndex; - } - - protected List items = new ArrayList(); - - /** - * subquads are numbered as follows: - *

                    -   *  2 | 3
                    -   *  --+--
                    -   *  0 | 1
                    -   * 
                    - */ - protected Node[] subnode = new Node[4]; - - public NodeBase() { - } - - public List getItems() { return items; } - - public boolean hasItems() { return ! items.isEmpty(); } - - public void add(Object item) - { - items.add(item); -//DEBUG itemCount++; -//DEBUG System.out.print(itemCount); - } - - /** - * Removes a single item from this subtree. - * - * @param itemEnv the envelope containing the item - * @param item the item to remove - * @return true if the item was found and removed - */ - public boolean remove(Envelope itemEnv, Object item) - { - // use envelope to restrict nodes scanned - if (! isSearchMatch(itemEnv)) - return false; - - boolean found = false; - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - found = subnode[i].remove(itemEnv, item); - if (found) { - // trim subtree if empty - if (subnode[i].isPrunable()) - subnode[i] = null; - break; - } - } - } - // if item was found lower down, don't need to search for it here - if (found) return found; - // otherwise, try and remove the item from the list of items in this node - found = items.remove(item); - return found; - } - - public boolean isPrunable() - { - return ! (hasChildren() || hasItems()); - } - - public boolean hasChildren() - { - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) - return true; - } - return false; - } - - public boolean isEmpty() - { - boolean isEmpty = true; - if (! items.isEmpty()) isEmpty = false; - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - if (! subnode[i].isEmpty() ) - isEmpty = false; - } - } - return isEmpty; - } - - //<> Sounds like this method adds resultItems to items - //(like List#addAll). Perhaps it should be renamed to "addAllItemsTo" [Jon Aquino] - public List addAllItems(List resultItems) - { - // this node may have items as well as subnodes (since items may not - // be wholely contained in any single subnode - resultItems.addAll(this.items); - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - subnode[i].addAllItems(resultItems); - } - } - return resultItems; - } - protected abstract boolean isSearchMatch(Envelope searchEnv); - - public void addAllItemsFromOverlapping(Envelope searchEnv, List resultItems) - { - if (! isSearchMatch(searchEnv)) - return; - - // this node may have items as well as subnodes (since items may not - // be wholely contained in any single subnode - resultItems.addAll(items); - - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - subnode[i].addAllItemsFromOverlapping(searchEnv, resultItems); - } - } - } - - public void visit(Envelope searchEnv, ItemVisitor visitor) - { - if (! isSearchMatch(searchEnv)) - return; - - // this node may have items as well as subnodes (since items may not - // be wholely contained in any single subnode - visitItems(searchEnv, visitor); - - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - subnode[i].visit(searchEnv, visitor); - } - } - } - - private void visitItems(Envelope searchEnv, ItemVisitor visitor) - { - // would be nice to filter items based on search envelope, but can't until they contain an envelope - for (Iterator i = items.iterator(); i.hasNext(); ) { - visitor.visitItem(i.next()); - } - } - -//<> In Samet's terminology, I think what we're returning here is -//actually level+1 rather than depth. (See p. 4 of his book) [Jon Aquino] - int depth() - { - int maxSubDepth = 0; - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - int sqd = subnode[i].depth(); - if (sqd > maxSubDepth) - maxSubDepth = sqd; - } - } - return maxSubDepth + 1; - } - - int size() - { - int subSize = 0; - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - subSize += subnode[i].size(); - } - } - return subSize + items.size(); - } - - int getNodeCount() - { - int subSize = 0; - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - subSize += subnode[i].size(); - } - } - return subSize + 1; - } - - -/** - * Visit all boundaries of all subnodes - * @param boundary - * @param visitor - */ -public void queryBoundary(Envelope boundary, ItemVisitor visitor) - { - - - //This flag marks whether this node is containing any subnodes. Once we find one subnode exists, - //set the flag to true. - boolean hasSubnodes=false; - - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - - hasSubnodes=true; - } - } - //If we find no subnodes, we know this is a leaf node. Record the boundary of this leaf node and return. - if(hasSubnodes==false) - { - visitor.visitItem(boundary); - return; - } - //If we can go here, we find this node is a non-leaf node. We should go deeper. - for (int i = 0; i < 4; i++) { - if (subnode[i] != null) { - - hasSubnodes=true; - subnode[i].queryBoundary(subnode[i].getEnvelope(),visitor); - } - } - - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/Quadtree.java b/src/main/java/com/vividsolutions/jts/index/quadtree/Quadtree.java deleted file mode 100644 index 5c10691412..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/Quadtree.java +++ /dev/null @@ -1,284 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.index.*; -/** - * A Quadtree is a spatial index structure for efficient range querying - * of items bounded by 2D rectangles. - * {@link Geometry}s can be indexed by using their - * {@link Envelope}s. - * Any type of Object can also be indexed as - * long as it has an extent that can be represented by an {@link Envelope}. - *

                    - * This Quadtree index provides a primary filter - * for range rectangle queries. The various query methods return a list of - * all items which may intersect the query rectangle. Note that - * it may thus return items which do not in fact intersect the query rectangle. - * A secondary filter is required to test for actual intersection - * between the query rectangle and the envelope of each candidate item. - * The secondary filter may be performed explicitly, - * or it may be provided implicitly by subsequent operations executed on the items - * (for instance, if the index query is followed by computing a spatial predicate - * between the query geometry and tree items, - * the envelope intersection check is performed automatically. - *

                    - * This implementation does not require specifying the extent of the inserted - * items beforehand. It will automatically expand to accomodate any extent - * of dataset. - *

                    - * This data structure is also known as an MX-CIF quadtree - * following the terminology of Samet and others. - * - * @version 1.7 - */ -/** - * @author sparkadmin - * - */ -/** - * @author sparkadmin - * - */ -public class Quadtree - implements SpatialIndex, Serializable -{ - private static final long serialVersionUID = -7461163625812743604L; - - /** - * Ensure that the envelope for the inserted item has non-zero extents. - * Use the current minExtent to pad the envelope, if necessary - */ - public static Envelope ensureExtent(Envelope itemEnv, double minExtent) - { - //The names "ensureExtent" and "minExtent" are misleading -- sounds like - //this method ensures that the extents are greater than minExtent. - //Perhaps we should rename them to "ensurePositiveExtent" and "defaultExtent". - //[Jon Aquino] - double minx = itemEnv.getMinX(); - double maxx = itemEnv.getMaxX(); - double miny = itemEnv.getMinY(); - double maxy = itemEnv.getMaxY(); - // has a non-zero extent - if (minx != maxx && miny != maxy) return itemEnv; - - // pad one or both extents - if (minx == maxx) { - minx = minx - minExtent / 2.0; - maxx = minx + minExtent / 2.0; - } - if (miny == maxy) { - miny = miny - minExtent / 2.0; - maxy = miny + minExtent / 2.0; - } - return new Envelope(minx, maxx, miny, maxy); - } - - private Root root; - /** - - * minExtent is the minimum envelope extent of all items - * inserted into the tree so far. It is used as a heuristic value - * to construct non-zero envelopes for features with zero X and/or Y extent. - * Start with a non-zero extent, in case the first feature inserted has - * a zero extent in both directions. This value may be non-optimal, but - * only one feature will be inserted with this value. - **/ - private double minExtent = 1.0; - - /** - * Constructs a Quadtree with zero items. - */ - public Quadtree() - { - root = new Root(); - } - - /** - * Returns the number of levels in the tree. - */ - public int depth() - { - //I don't think it's possible for root to be null. Perhaps we should - //remove the check. [Jon Aquino] - //Or make an assertion [Jon Aquino 10/29/2003] - if (root != null) return root.depth(); - return 0; - } - - /** - * Tests whether the index contains any items. - * - * @return true if the index does not contain any items - */ - public boolean isEmpty() - { - if (root == null) return true; - return false; - } - - /** - * Returns the number of items in the tree. - * - * @return the number of items in the tree - */ - public int size() - { - if (root != null) return root.size(); - return 0; - } - - public void insert(Envelope itemEnv, Object item) - { - collectStats(itemEnv); - Envelope insertEnv = ensureExtent(itemEnv, minExtent); - root.insert(insertEnv, item); - } - - /** - * Removes a single item from the tree. - * - * @param itemEnv the Envelope of the item to be removed - * @param item the item to remove - * @return true if the item was found (and thus removed) - */ - public boolean remove(Envelope itemEnv, Object item) - { - Envelope posEnv = ensureExtent(itemEnv, minExtent); - return root.remove(posEnv, item); - } - -/* - public List OLDquery(Envelope searchEnv) - { - /** - * the items that are matched are the items in quads which - * overlap the search envelope - */ - /* - List foundItems = new ArrayList(); - root.addAllItemsFromOverlapping(searchEnv, foundItems); - return foundItems; - } -*/ - - /** - * Queries the tree and returns items which may lie in the given search envelope. - * Precisely, the items that are returned are all items in the tree - * whose envelope may intersect the search Envelope. - * Note that some items with non-intersecting envelopes may be returned as well; - * the client is responsible for filtering these out. - * In most situations there will be many items in the tree which do not - * intersect the search envelope and which are not returned - thus - * providing improved performance over a simple linear scan. - * - * @param searchEnv the envelope of the desired query area. - * @return a List of items which may intersect the search envelope - */ - public List query(Envelope searchEnv) - { - /** - * the items that are matched are the items in quads which - * overlap the search envelope - */ - ArrayListVisitor visitor = new ArrayListVisitor(); - query(searchEnv, visitor); - return visitor.getItems(); - } - - /** - * Queries the tree and visits items which may lie in the given search envelope. - * Precisely, the items that are visited are all items in the tree - * whose envelope may intersect the search Envelope. - * Note that some items with non-intersecting envelopes may be visited as well; - * the client is responsible for filtering these out. - * In most situations there will be many items in the tree which do not - * intersect the search envelope and which are not visited - thus - * providing improved performance over a simple linear scan. - * - * @param searchEnv the envelope of the desired query area. - * @param visitor a visitor object which is passed the visited items - */ - public void query(Envelope searchEnv, ItemVisitor visitor) - { - /** - * the items that are matched are the items in quads which - * overlap the search envelope - */ - root.visit(searchEnv, visitor); - } - - /** - * Return a list of all items in the Quadtree - */ - public List queryAll() - { - List foundItems = new ArrayList(); - root.addAllItems(foundItems); - return foundItems; - } - - private void collectStats(Envelope itemEnv) - { - double delX = itemEnv.getWidth(); - if (delX < minExtent && delX > 0.0) - minExtent = delX; - - double delY = itemEnv.getHeight(); - if (delY < minExtent && delY > 0.0) - minExtent = delY; - } - -/** - * This method is to find the boundaries of leaf nodes. Note that: - * this quad-tree may have items stored on its non-leaf nodes. Thus - * boundaries returned by this method cannot cover all items. - * @return Return the list of boundaries we find. - */ -public List queryBoundary() - { - List grids=new ArrayList(); - ArrayListVisitor visitor = new ArrayListVisitor(); - root.queryBoundary(new Envelope(0.0,0.0,0.0,0.0),visitor); - grids=visitor.getItems(); - - return grids; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/quadtree/Root.java b/src/main/java/com/vividsolutions/jts/index/quadtree/Root.java deleted file mode 100644 index f4fd76dcac..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/quadtree/Root.java +++ /dev/null @@ -1,120 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.quadtree; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.util.Assert; - -/** - * QuadRoot is the root of a single Quadtree. It is centred at the origin, - * and does not have a defined extent. - * - * @version 1.7 - */ -public class Root - extends NodeBase -{ - - // the singleton root quad is centred at the origin. - private static final Coordinate origin = new Coordinate(0.0, 0.0); - - public Root() - { - } - - /** - * Insert an item into the quadtree this is the root of. - */ - public void insert(Envelope itemEnv, Object item) - { - int index = getSubnodeIndex(itemEnv, origin.x, origin.y); - // if index is -1, itemEnv must cross the X or Y axis. - if (index == -1) { - add(item); - return; - } - /** - * the item must be contained in one quadrant, so insert it into the - * tree for that quadrant (which may not yet exist) - */ - Node node = subnode[index]; - /** - * If the subquad doesn't exist or this item is not contained in it, - * have to expand the tree upward to contain the item. - */ - - if (node == null || ! node.getEnvelope().contains(itemEnv)) { - Node largerNode = Node.createExpanded(node, itemEnv); - subnode[index] = largerNode; - } - /** - * At this point we have a subquad which exists and must contain - * contains the env for the item. Insert the item into the tree. - */ - insertContained(subnode[index], itemEnv, item); - //System.out.println("depth = " + root.depth() + " size = " + root.size()); - //System.out.println(" size = " + size()); - } - - /** - * insert an item which is known to be contained in the tree rooted at - * the given QuadNode root. Lower levels of the tree will be created - * if necessary to hold the item. - */ - private void insertContained(Node tree, Envelope itemEnv, Object item) - { - Assert.isTrue(tree.getEnvelope().contains(itemEnv)); - /** - * Do NOT create a new quad for zero-area envelopes - this would lead - * to infinite recursion. Instead, use a heuristic of simply returning - * the smallest existing quad containing the query - */ - boolean isZeroX = IntervalSize.isZeroWidth(itemEnv.getMinX(), itemEnv.getMaxX()); - boolean isZeroY = IntervalSize.isZeroWidth(itemEnv.getMinY(), itemEnv.getMaxY()); - NodeBase node; - if (isZeroX || isZeroY) - node = tree.find(itemEnv); - else - node = tree.getNode(itemEnv); - node.add(item); - } - - protected boolean isSearchMatch(Envelope searchEnv) - { - return true; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/AbstractNode.java b/src/main/java/com/vividsolutions/jts/index/strtree/AbstractNode.java deleted file mode 100644 index 2df956a6aa..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/AbstractNode.java +++ /dev/null @@ -1,144 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; -import com.vividsolutions.jts.util.*; - -import java.io.Serializable; -import java.util.*; - -/** - * A node of an {@link AbstractSTRtree}. A node is one of: - *

                      - *
                    • empty - *
                    • an interior node containing child {@link AbstractNode}s - *
                    • a leaf node containing data items ({@link ItemBoundable}s). - *
                    - * A node stores the bounds of its children, and its level within the index tree. - * - * @version 1.7 - */ -public abstract class AbstractNode implements Boundable, Serializable { - /** - * - */ - private static final long serialVersionUID = 6493722185909573708L; - - private ArrayList childBoundables = new ArrayList(); - private Object bounds = null; - private int level; - - /** - * Default constructor required for serialization. - */ - public AbstractNode() { - } - - /** - * Constructs an AbstractNode at the given level in the tree - * @param level 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the - * root node will have the highest level - */ - public AbstractNode(int level) { - this.level = level; - } - - /** - * Returns either child {@link AbstractNode}s, or if this is a leaf node, real data (wrapped - * in {@link ItemBoundable}s). - */ - public List getChildBoundables() { - return childBoundables; - } - - /** - * Returns a representation of space that encloses this Boundable, - * preferably not much bigger than this Boundable's boundary yet fast to - * test for intersection with the bounds of other Boundables. The class of - * object returned depends on the subclass of AbstractSTRtree. - * - * @return an Envelope (for STRtrees), an Interval (for SIRtrees), or other - * object (for other subclasses of AbstractSTRtree) - * @see AbstractSTRtree.IntersectsOp - */ - protected abstract Object computeBounds(); - - /** - * Gets the bounds of this node - * - * @return the object representing bounds in this index - */ - public Object getBounds() { - if (bounds == null) { - bounds = computeBounds(); - } - return bounds; - } - - /** - * Returns 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the - * root node will have the highest level - */ - public int getLevel() { - return level; - } - - /** - * Gets the count of the {@link Boundable}s at this node. - * - * @return the count of boundables at this node - */ - public int size() - { - return childBoundables.size(); - } - - /** - * Tests whether there are any {@link Boundable}s at this node. - * - * @return true if there are boundables at this node - */ - public boolean isEmpty() - { - return childBoundables.isEmpty(); - } - - /** - * Adds either an AbstractNode, or if this is a leaf node, a data object - * (wrapped in an ItemBoundable) - */ - public void addChildBoundable(Boundable childBoundable) { - Assert.isTrue(bounds == null); - childBoundables.add(childBoundable); - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java b/src/main/java/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java deleted file mode 100644 index 4a4a5f11ef..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java +++ /dev/null @@ -1,519 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.index.ItemVisitor; -import com.vividsolutions.jts.util.*; - -import java.io.Serializable; -import java.util.*; - -/** - * Base class for STRtree and SIRtree. STR-packed R-trees are described in: - * P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With - * Application To GIS. Morgan Kaufmann, San Francisco, 2002. - *

                    - * This implementation is based on {@link Boundable}s rather than {@link AbstractNode}s, - * because the STR algorithm operates on both nodes and - * data, both of which are treated as Boundables. - *

                    - * This class is thread-safe. Building the tree is synchronized, - * and querying is stateless. - * - * @see STRtree - * @see SIRtree - * - * @version 1.7 - */ -public abstract class AbstractSTRtree implements Serializable { - - /** - * - */ - private static final long serialVersionUID = -3886435814360241337L; - - /** - * A test for intersection between two bounds, necessary because subclasses - * of AbstractSTRtree have different implementations of bounds. - */ - protected static interface IntersectsOp { - /** - * For STRtrees, the bounds will be Envelopes; for SIRtrees, Intervals; - * for other subclasses of AbstractSTRtree, some other class. - * @param aBounds the bounds of one spatial object - * @param bBounds the bounds of another spatial object - * @return whether the two bounds intersect - */ - boolean intersects(Object aBounds, Object bBounds); - } - - protected AbstractNode root; - - private boolean built = false; - /** - * Set to null when index is built, to avoid retaining memory. - */ - private ArrayList itemBoundables = new ArrayList(); - - private int nodeCapacity; - - private static final int DEFAULT_NODE_CAPACITY = 10; - - /** - * Constructs an AbstractSTRtree with the - * default node capacity. - */ - public AbstractSTRtree() { - this(DEFAULT_NODE_CAPACITY); - } - - /** - * Constructs an AbstractSTRtree with the specified maximum number of child - * nodes that a node may have - * - * @param nodeCapacity the maximum number of child nodes in a node - */ - public AbstractSTRtree(int nodeCapacity) { - Assert.isTrue(nodeCapacity > 1, "Node capacity must be greater than 1"); - this.nodeCapacity = nodeCapacity; - } - - /** - * Creates parent nodes, grandparent nodes, and so forth up to the root - * node, for the data that has been inserted into the tree. Can only be - * called once, and thus can be called only after all of the data has been - * inserted into the tree. - */ - public synchronized void build() { - if (built) return; - root = itemBoundables.isEmpty() - ? createNode(0) - : createHigherLevels(itemBoundables, -1); - // the item list is no longer needed - itemBoundables = null; - built = true; - } - - protected abstract AbstractNode createNode(int level); - - /** - * Sorts the childBoundables then divides them into groups of size M, where - * M is the node capacity. - */ - protected List createParentBoundables(List childBoundables, int newLevel) { - Assert.isTrue(!childBoundables.isEmpty()); - ArrayList parentBoundables = new ArrayList(); - parentBoundables.add(createNode(newLevel)); - ArrayList sortedChildBoundables = new ArrayList(childBoundables); - Collections.sort(sortedChildBoundables, getComparator()); - for (Iterator i = sortedChildBoundables.iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (lastNode(parentBoundables).getChildBoundables().size() == getNodeCapacity()) { - parentBoundables.add(createNode(newLevel)); - } - lastNode(parentBoundables).addChildBoundable(childBoundable); - } - return parentBoundables; - } - - protected AbstractNode lastNode(List nodes) { - return (AbstractNode) nodes.get(nodes.size() - 1); - } - - protected static int compareDoubles(double a, double b) { - return a > b ? 1 - : a < b ? -1 - : 0; - } - - /** - * Creates the levels higher than the given level - * - * @param boundablesOfALevel - * the level to build on - * @param level - * the level of the Boundables, or -1 if the boundables are item - * boundables (that is, below level 0) - * @return the root, which may be a ParentNode or a LeafNode - */ - private AbstractNode createHigherLevels(List boundablesOfALevel, int level) { - Assert.isTrue(!boundablesOfALevel.isEmpty()); - List parentBoundables = createParentBoundables(boundablesOfALevel, level + 1); - if (parentBoundables.size() == 1) { - return (AbstractNode) parentBoundables.get(0); - } - return createHigherLevels(parentBoundables, level + 1); - } - - public AbstractNode getRoot() - { - build(); - return root; - } - - /** - * Returns the maximum number of child nodes that a node may have - */ - public int getNodeCapacity() { return nodeCapacity; } - - /** - * Tests whether the index contains any items. - * This method does not build the index, - * so items can still be inserted after it has been called. - * - * @return true if the index does not contain any items - */ - public boolean isEmpty() - { - if (! built) return itemBoundables.isEmpty(); - return root.isEmpty(); - } - - protected int size() { - if (isEmpty()) { - return 0; - } - build(); - return size(root); - } - - protected int size(AbstractNode node) - { - int size = 0; - for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (childBoundable instanceof AbstractNode) { - size += size((AbstractNode) childBoundable); - } - else if (childBoundable instanceof ItemBoundable) { - size += 1; - } - } - return size; - } - - protected int depth() { - if (isEmpty()) { - return 0; - } - build(); - return depth(root); - } - - protected int depth(AbstractNode node) - { - int maxChildDepth = 0; - for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (childBoundable instanceof AbstractNode) { - int childDepth = depth((AbstractNode) childBoundable); - if (childDepth > maxChildDepth) - maxChildDepth = childDepth; - } - } - return maxChildDepth + 1; - } - - - protected void insert(Object bounds, Object item) { - Assert.isTrue(!built, "Cannot insert items into an STR packed R-tree after it has been built."); - itemBoundables.add(new ItemBoundable(bounds, item)); - } - - /** - * Also builds the tree, if necessary. - */ - protected List query(Object searchBounds) { - build(); - ArrayList matches = new ArrayList(); - if (isEmpty()) { - //Assert.isTrue(root.getBounds() == null); - return matches; - } - if (getIntersectsOp().intersects(root.getBounds(), searchBounds)) { - query(searchBounds, root, matches); - } - return matches; - } - - /** - * Also builds the tree, if necessary. - */ - protected void query(Object searchBounds, ItemVisitor visitor) { - build(); - if (isEmpty()) { - // nothing in tree, so return - //Assert.isTrue(root.getBounds() == null); - return; - } - if (getIntersectsOp().intersects(root.getBounds(), searchBounds)) { - query(searchBounds, root, visitor); - } - } - - /** - * @return a test for intersection between two bounds, necessary because subclasses - * of AbstractSTRtree have different implementations of bounds. - * @see IntersectsOp - */ - protected abstract IntersectsOp getIntersectsOp(); - - private void query(Object searchBounds, AbstractNode node, List matches) { - List childBoundables = node.getChildBoundables(); - for (int i = 0; i < childBoundables.size(); i++) { - Boundable childBoundable = (Boundable) childBoundables.get(i); - if (! getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds)) { - continue; - } - if (childBoundable instanceof AbstractNode) { - query(searchBounds, (AbstractNode) childBoundable, matches); - } - else if (childBoundable instanceof ItemBoundable) { - matches.add(((ItemBoundable)childBoundable).getItem()); - } - else { - Assert.shouldNeverReachHere(); - } - } - } - - private void query(Object searchBounds, AbstractNode node, ItemVisitor visitor) { - List childBoundables = node.getChildBoundables(); - for (int i = 0; i < childBoundables.size(); i++) { - Boundable childBoundable = (Boundable) childBoundables.get(i); - if (! getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds)) { - continue; - } - if (childBoundable instanceof AbstractNode) { - query(searchBounds, (AbstractNode) childBoundable, visitor); - } - else if (childBoundable instanceof ItemBoundable) { - visitor.visitItem(((ItemBoundable)childBoundable).getItem()); - } - else { - Assert.shouldNeverReachHere(); - } - } - } - - /** - * Gets a tree structure (as a nested list) - * corresponding to the structure of the items and nodes in this tree. - *

                    - * The returned {@link List}s contain either {@link Object} items, - * or Lists which correspond to subtrees of the tree - * Subtrees which do not contain any items are not included. - *

                    - * Builds the tree if necessary. - * - * @return a List of items and/or Lists - */ - public List itemsTree() - { - build(); - - List valuesTree = itemsTree(root); - if (valuesTree == null) - return new ArrayList(); - return valuesTree; - } - - private List itemsTree(AbstractNode node) - { - List valuesTreeForNode = new ArrayList(); - for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (childBoundable instanceof AbstractNode) { - List valuesTreeForChild = itemsTree((AbstractNode) childBoundable); - // only add if not null (which indicates an item somewhere in this tree - if (valuesTreeForChild != null) - valuesTreeForNode.add(valuesTreeForChild); - } - else if (childBoundable instanceof ItemBoundable) { - valuesTreeForNode.add(((ItemBoundable)childBoundable).getItem()); - } - else { - Assert.shouldNeverReachHere(); - } - } - if (valuesTreeForNode.size() <= 0) - return null; - return valuesTreeForNode; - } - - /** - * Removes an item from the tree. - * (Builds the tree, if necessary.) - */ - protected boolean remove(Object searchBounds, Object item) { - build(); - if (getIntersectsOp().intersects(root.getBounds(), searchBounds)) { - return remove(searchBounds, root, item); - } - return false; - } - - private boolean removeItem(AbstractNode node, Object item) - { - Boundable childToRemove = null; - for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (childBoundable instanceof ItemBoundable) { - if ( ((ItemBoundable) childBoundable).getItem() == item) - childToRemove = childBoundable; - } - } - if (childToRemove != null) { - node.getChildBoundables().remove(childToRemove); - return true; - } - return false; - } - - private boolean remove(Object searchBounds, AbstractNode node, Object item) { - // first try removing item from this node - boolean found = removeItem(node, item); - if (found) - return true; - - AbstractNode childToPrune = null; - // next try removing item from lower nodes - for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (!getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds)) { - continue; - } - if (childBoundable instanceof AbstractNode) { - found = remove(searchBounds, (AbstractNode) childBoundable, item); - // if found, record child for pruning and exit - if (found) { - childToPrune = (AbstractNode) childBoundable; - break; - } - } - } - // prune child if possible - if (childToPrune != null) { - if (childToPrune.getChildBoundables().isEmpty()) { - node.getChildBoundables().remove(childToPrune); - } - } - return found; - } - - protected List boundablesAtLevel(int level) { - ArrayList boundables = new ArrayList(); - boundablesAtLevel(level, root, boundables); - return boundables; - } - - /** - * @param level -1 to get items - */ - private void boundablesAtLevel(int level, AbstractNode top, Collection boundables) { - Assert.isTrue(level > -2); - if (top.getLevel() == level) { - boundables.add(top); - return; - } - for (Iterator i = top.getChildBoundables().iterator(); i.hasNext(); ) { - Boundable boundable = (Boundable) i.next(); - if (boundable instanceof AbstractNode) { - boundablesAtLevel(level, (AbstractNode)boundable, boundables); - } - else { - Assert.isTrue(boundable instanceof ItemBoundable); - if (level == -1) { boundables.add(boundable); } - } - } - return; - } - - protected abstract Comparator getComparator(); -/** - * This function traverses the boundaries of all leaf nodes. - * This function should be called after all insertions. - * @return The list of lea nodes boundaries - */ -protected List queryBoundary() - { - build(); - List boundaries = new ArrayList(); - if (isEmpty()) { - //Assert.isTrue(root.getBounds() == null); - //If the root is empty, we stop traversing. This should not happen. - return boundaries; - } - - queryBoundary(root, boundaries); - - return boundaries; - } -/** - * This function is to traverse the children of the root. - * @param node - * @param boundaries - */ -private void queryBoundary(AbstractNode node, List boundaries) { - List childBoundables = node.getChildBoundables(); - boolean flagLeafnode=true; - for (int i = 0; i < childBoundables.size(); i++) { - Boundable childBoundable = (Boundable) childBoundables.get(i); - if (childBoundable instanceof AbstractNode) { - //We find this is not a leaf node. - flagLeafnode=false; - break; - - } - } - if(flagLeafnode==true) - { - boundaries.add((Envelope)node.getBounds()); - return; - } - else - { - for (int i = 0; i < childBoundables.size(); i++) - { - Boundable childBoundable = (Boundable) childBoundables.get(i); - if (childBoundable instanceof AbstractNode) - { - queryBoundary((AbstractNode) childBoundable, boundaries); - } - - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/Boundable.java b/src/main/java/com/vividsolutions/jts/index/strtree/Boundable.java deleted file mode 100644 index d9a1fcc16c..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/Boundable.java +++ /dev/null @@ -1,51 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -/** - * A spatial object in an AbstractSTRtree. - * - * @version 1.7 - */ -public interface Boundable { - /** - * Returns a representation of space that encloses this Boundable, preferably - * not much bigger than this Boundable's boundary yet fast to test for intersection - * with the bounds of other Boundables. The class of object returned depends - * on the subclass of AbstractSTRtree. - * @return an Envelope (for STRtrees), an Interval (for SIRtrees), or other object - * (for other subclasses of AbstractSTRtree) - */ - Object getBounds(); -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/BoundablePair.java b/src/main/java/com/vividsolutions/jts/index/strtree/BoundablePair.java deleted file mode 100644 index 9f2839b994..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/BoundablePair.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.util.PriorityQueue; - -/** - * A pair of {@link Boundable}s, whose leaf items - * support a distance metric between them. - * Used to compute the distance between the members, - * and to expand a member relative to the other - * in order to produce new branches of the - * Branch-and-Bound evaluation tree. - * Provides an ordering based on the distance between the members, - * which allows building a priority queue by minimum distance. - * - * @author Martin Davis - * - */ -class BoundablePair - implements Comparable -{ - private Boundable boundable1; - private Boundable boundable2; - private double distance; - private ItemDistance itemDistance; - //private double maxDistance = -1.0; - - public BoundablePair(Boundable boundable1, Boundable boundable2, ItemDistance itemDistance) - { - this.boundable1 = boundable1; - this.boundable2 = boundable2; - this.itemDistance = itemDistance; - distance = distance(); - } - - /** - * Gets one of the member {@link Boundable}s in the pair - * (indexed by [0, 1]). - * - * @param i the index of the member to return (0 or 1) - * @return the chosen member - */ - public Boundable getBoundable(int i) - { - if (i == 0) return boundable1; - return boundable2; - } - - /** - * Computes the distance between the {@link Boundable}s in this pair. - * The boundables are either composites or leaves. - * If either is composite, the distance is computed as the minimum distance - * between the bounds. - * If both are leaves, the distance is computed by {@link #itemDistance(ItemBoundable, ItemBoundable)}. - * - * @return - */ - private double distance() - { - // if items, compute exact distance - if (isLeaves()) { - return itemDistance.distance((ItemBoundable) boundable1, - (ItemBoundable) boundable2); - } - // otherwise compute distance between bounds of boundables - return ((Envelope) boundable1.getBounds()).distance( - ((Envelope) boundable2.getBounds())); - } - - - /* - public double getMaximumDistance() - { - if (maxDistance < 0.0) - maxDistance = maxDistance(); - return maxDistance; - } - */ - - /* - private double maxDistance() - { - return maximumDistance( - (Envelope) boundable1.getBounds(), - (Envelope) boundable2.getBounds()); - } - - private static double maximumDistance(Envelope env1, Envelope env2) - { - double minx = Math.min(env1.getMinX(), env2.getMinX()); - double miny = Math.min(env1.getMinY(), env2.getMinY()); - double maxx = Math.max(env1.getMaxX(), env2.getMaxX()); - double maxy = Math.max(env1.getMaxY(), env2.getMaxY()); - Coordinate min = new Coordinate(minx, miny); - Coordinate max = new Coordinate(maxx, maxy); - return min.distance(max); - } - */ - - /** - * Gets the minimum possible distance between the Boundables in - * this pair. - * If the members are both items, this will be the - * exact distance between them. - * Otherwise, this distance will be a lower bound on - * the distances between the items in the members. - * - * @return the exact or lower bound distance for this pair - */ - public double getDistance() { return distance; } - - /** - * Compares two pairs based on their minimum distances - */ - public int compareTo(Object o) - { - BoundablePair nd = (BoundablePair) o; - if (distance < nd.distance) return -1; - if (distance > nd.distance) return 1; - return 0; - } - - /** - * Tests if both elements of the pair are leaf nodes - * - * @return true if both pair elements are leaf nodes - */ - public boolean isLeaves() - { - return ! (isComposite(boundable1) || isComposite(boundable2)); - } - - public static boolean isComposite(Object item) - { - return (item instanceof AbstractNode); - } - - private static double area(Boundable b) - { - return ((Envelope) b.getBounds()).getArea(); - } - - /** - * For a pair which is not a leaf - * (i.e. has at least one composite boundable) - * computes a list of new pairs - * from the expansion of the larger boundable. - * - */ - public void expandToQueue(PriorityQueue priQ, double minDistance) - { - boolean isComp1 = isComposite(boundable1); - boolean isComp2 = isComposite(boundable2); - - /** - * HEURISTIC: If both boundable are composite, - * choose the one with largest area to expand. - * Otherwise, simply expand whichever is composite. - */ - if (isComp1 && isComp2) { - if (area(boundable1) > area(boundable2)) { - expand(boundable1, boundable2, priQ, minDistance); - return; - } - else { - expand(boundable2, boundable1, priQ, minDistance); - return; - } - } - else if (isComp1) { - expand(boundable1, boundable2, priQ, minDistance); - return; - } - else if (isComp2) { - expand(boundable2, boundable1, priQ, minDistance); - return; - } - - throw new IllegalArgumentException("neither boundable is composite"); - } - - private void expand(Boundable bndComposite, Boundable bndOther, - PriorityQueue priQ, double minDistance) - { - List children = ((AbstractNode) bndComposite).getChildBoundables(); - for (Iterator i = children.iterator(); i.hasNext(); ) { - Boundable child = (Boundable) i.next(); - BoundablePair bp = new BoundablePair(child, bndOther, itemDistance); - // only add to queue if this pair might contain the closest points - // MD - it's actually faster to construct the object rather than called distance(child, bndOther)! - if (bp.getDistance() < minDistance) { - priQ.add(bp); - } - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java b/src/main/java/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java deleted file mode 100644 index cfbc63a3ee..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java +++ /dev/null @@ -1,63 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.index.strtree; - -import com.vividsolutions.jts.geom.Geometry; - -/** - * An ItemDistance function for - * items which are {@link Geometry}s, - * using the {@link Geometry#distance(Geometry)} method. - * - * @author Martin Davis - * - */ -public class GeometryItemDistance -implements ItemDistance -{ - /** - * Computes the distance between two {@link Geometry} items, - * using the {@link Geometry#distance(Geometry)} method. - * - * @param item1 an item which is a Geometry - * @param item2 an item which is a Geometry - * @return the distance between the geometries - * @throws ClassCastException if either item is not a Geometry - */ - public double distance(ItemBoundable item1, ItemBoundable item2) { - Geometry g1 = (Geometry) item1.getItem(); - Geometry g2 = (Geometry) item2.getItem(); - return g1.distance(g2); - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/Interval.java b/src/main/java/com/vividsolutions/jts/index/strtree/Interval.java deleted file mode 100644 index bc1ef2b71a..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/Interval.java +++ /dev/null @@ -1,78 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import com.vividsolutions.jts.util.*; - -/** - * A contiguous portion of 1D-space. Used internally by SIRtree. - * @see SIRtree - * - * @version 1.7 - */ -public class Interval { - - public Interval(Interval other) { - this(other.min, other.max); - } - - public Interval(double min, double max) { - Assert.isTrue(min <= max); - this.min = min; - this.max = max; - } - - private double min; - private double max; - - public double getCentre() { return (min+max)/2; } - - /** - * @return this - */ - public Interval expandToInclude(Interval other) { - max = Math.max(max, other.max); - min = Math.min(min, other.min); - return this; - } - - public boolean intersects(Interval other) { - return !(other.min > max || other.max < min); - } - public boolean equals(Object o) { - if (! (o instanceof Interval)) { return false; } - Interval other = (Interval) o; - return min == other.min && max == other.max; - } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/ItemBoundable.java b/src/main/java/com/vividsolutions/jts/index/strtree/ItemBoundable.java deleted file mode 100644 index 621f54c762..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/ItemBoundable.java +++ /dev/null @@ -1,58 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import java.io.Serializable; - -/** - * Boundable wrapper for a non-Boundable spatial object. Used internally by - * AbstractSTRtree. - * - * @version 1.7 - */ -public class ItemBoundable implements Boundable, Serializable { - private Object bounds; - private Object item; - - public ItemBoundable(Object bounds, Object item) { - this.bounds = bounds; - this.item = item; - } - - public Object getBounds() { - return bounds; - } - - public Object getItem() { return item; } -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/ItemDistance.java b/src/main/java/com/vividsolutions/jts/index/strtree/ItemDistance.java deleted file mode 100644 index a8e1a88bcd..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/ItemDistance.java +++ /dev/null @@ -1,58 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.index.strtree; - - -/** - * A function method which computes the distance - * between two {@link ItemBoundable}s in an {@link STRtree}. - * Used for Nearest Neighbour searches. - * - * @author Martin Davis - * - */ -public interface ItemDistance -{ - /** - * Computes the distance between two items. - * - * @param item1 - * @param item2 - * @return the distance between the items - * - * @throws IllegalArgumentException if the metric is not applicable to the arguments - */ - double distance(ItemBoundable item1, ItemBoundable item2); - -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/SIRtree.java b/src/main/java/com/vividsolutions/jts/index/strtree/SIRtree.java deleted file mode 100644 index de21b71a03..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/SIRtree.java +++ /dev/null @@ -1,130 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -/** - * One-dimensional version of an STR-packed R-tree. SIR stands for - * "Sort-Interval-Recursive". STR-packed R-trees are described in: - * P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With - * Application To GIS. Morgan Kaufmann, San Francisco, 2002. - *

                    - * This class is thread-safe. Building the tree is synchronized, - * and querying is stateless. - * - * @see STRtree - * - * @version 1.7 - */ -public class SIRtree extends AbstractSTRtree { - - private Comparator comparator = new Comparator() { - public int compare(Object o1, Object o2) { - return compareDoubles( - ((Interval)((Boundable)o1).getBounds()).getCentre(), - ((Interval)((Boundable)o2).getBounds()).getCentre()); - } - }; - - private IntersectsOp intersectsOp = new IntersectsOp() { - public boolean intersects(Object aBounds, Object bBounds) { - return ((Interval)aBounds).intersects((Interval)bBounds); - } - }; - - /** - * Constructs an SIRtree with the default node capacity. - */ - public SIRtree() { this(10); } - - /** - * Constructs an SIRtree with the given maximum number of child nodes that - * a node may have - */ - public SIRtree(int nodeCapacity) { - super(nodeCapacity); - } - - protected AbstractNode createNode(int level) { - return new AbstractNode(level) { - protected Object computeBounds() { - Interval bounds = null; - for (Iterator i = getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (bounds == null) { - bounds = new Interval((Interval)childBoundable.getBounds()); - } - else { - bounds.expandToInclude((Interval)childBoundable.getBounds()); - } - } - return bounds; - } - }; - } - - /** - * Inserts an item having the given bounds into the tree. - */ - public void insert(double x1, double x2, Object item) { - super.insert(new Interval(Math.min(x1, x2), Math.max(x1, x2)), item); - } - - /** - * Returns items whose bounds intersect the given value. - */ - public List query(double x) { - return query(x, x); - } - - /** - * Returns items whose bounds intersect the given bounds. - * @param x1 possibly equal to x2 - */ - public List query(double x1, double x2) { - return super.query(new Interval(Math.min(x1, x2), Math.max(x1, x2))); - } - - protected IntersectsOp getIntersectsOp() { - return intersectsOp; - } - - protected Comparator getComparator() { - return comparator; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/strtree/STRtree.java b/src/main/java/com/vividsolutions/jts/index/strtree/STRtree.java deleted file mode 100644 index f733342d9e..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/strtree/STRtree.java +++ /dev/null @@ -1,543 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.strtree; - -import com.vividsolutions.jts.index.strtree.AbstractSTRtree; - -import java.io.Serializable; -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.util.PriorityQueue; -import com.vividsolutions.jts.index.*; - -/** - * A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. - * For two-dimensional spatial data. - *

                    - * The STR packed R-tree is simple to implement and maximizes space - * utilization; that is, as many leaves as possible are filled to capacity. - * Overlap between nodes is far less than in a basic R-tree. However, once the - * tree has been built (explicitly or on the first call to #query), items may - * not be added or removed. - *

                    - * Described in: P. Rigaux, Michel Scholl and Agnes Voisard. - * Spatial Databases With Application To GIS. - * Morgan Kaufmann, San Francisco, 2002. - *

                    - * This class is thread-safe. Building the tree is synchronized, - * and querying is stateless. - * - * @version 1.7 - */ -public class STRtree extends AbstractSTRtree -implements SpatialIndex, Serializable -{ - - private static final class STRtreeNode extends AbstractNode - { - private STRtreeNode(int level) - { - super(level); - } - - protected Object computeBounds() { - Envelope bounds = null; - for (Iterator i = getChildBoundables().iterator(); i.hasNext(); ) { - Boundable childBoundable = (Boundable) i.next(); - if (bounds == null) { - bounds = new Envelope((Envelope)childBoundable.getBounds()); - } - else { - bounds.expandToInclude((Envelope)childBoundable.getBounds()); - } - } - return bounds; - } - } - - /** - * - */ - private static final long serialVersionUID = 259274702368956900L; - - private static Comparator xComparator = - new Comparator() { - public int compare(Object o1, Object o2) { - return compareDoubles( - centreX((Envelope)((Boundable)o1).getBounds()), - centreX((Envelope)((Boundable)o2).getBounds())); - } - }; - private static Comparator yComparator = - new Comparator() { - public int compare(Object o1, Object o2) { - return compareDoubles( - centreY((Envelope)((Boundable)o1).getBounds()), - centreY((Envelope)((Boundable)o2).getBounds())); - } - }; - - private static double centreX(Envelope e) { - return avg(e.getMinX(), e.getMaxX()); - } - - private static double centreY(Envelope e) { - return avg(e.getMinY(), e.getMaxY()); - } - - private static double avg(double a, double b) { return (a + b) / 2d; } - - private static IntersectsOp intersectsOp = new IntersectsOp() { - public boolean intersects(Object aBounds, Object bBounds) { - return ((Envelope)aBounds).intersects((Envelope)bBounds); - } - }; - - /** - * Creates the parent level for the given child level. First, orders the items - * by the x-values of the midpoints, and groups them into vertical slices. - * For each slice, orders the items by the y-values of the midpoints, and - * group them into runs of size M (the node capacity). For each run, creates - * a new (parent) node. - */ - protected List createParentBoundables(List childBoundables, int newLevel) { - Assert.isTrue(!childBoundables.isEmpty()); - int minLeafCount = (int) Math.ceil((childBoundables.size() / (double) getNodeCapacity())); - ArrayList sortedChildBoundables = new ArrayList(childBoundables); - Collections.sort(sortedChildBoundables, xComparator); - List[] verticalSlices = verticalSlices(sortedChildBoundables, - (int) Math.ceil(Math.sqrt(minLeafCount))); - return createParentBoundablesFromVerticalSlices(verticalSlices, newLevel); - } - - private List createParentBoundablesFromVerticalSlices(List[] verticalSlices, int newLevel) { - Assert.isTrue(verticalSlices.length > 0); - List parentBoundables = new ArrayList(); - for (int i = 0; i < verticalSlices.length; i++) { - parentBoundables.addAll( - createParentBoundablesFromVerticalSlice(verticalSlices[i], newLevel)); - } - return parentBoundables; - } - - protected List createParentBoundablesFromVerticalSlice(List childBoundables, int newLevel) { - return super.createParentBoundables(childBoundables, newLevel); - } - - /** - * @param childBoundables Must be sorted by the x-value of the envelope midpoints - */ - protected List[] verticalSlices(List childBoundables, int sliceCount) { - int sliceCapacity = (int) Math.ceil(childBoundables.size() / (double) sliceCount); - List[] slices = new List[sliceCount]; - Iterator i = childBoundables.iterator(); - for (int j = 0; j < sliceCount; j++) { - slices[j] = new ArrayList(); - int boundablesAddedToSlice = 0; - while (i.hasNext() && boundablesAddedToSlice < sliceCapacity) { - Boundable childBoundable = (Boundable) i.next(); - slices[j].add(childBoundable); - boundablesAddedToSlice++; - } - } - return slices; - } - - private static final int DEFAULT_NODE_CAPACITY = 10; - - /** - * Constructs an STRtree with the default node capacity. - */ - public STRtree() - { - this(DEFAULT_NODE_CAPACITY); - } - - /** - * Constructs an STRtree with the given maximum number of child nodes that - * a node may have. - *

                    - * The minimum recommended capacity setting is 4. - * - */ - public STRtree(int nodeCapacity) { - super(nodeCapacity); - } - - protected AbstractNode createNode(int level) { - return new STRtreeNode(level); - } - - protected IntersectsOp getIntersectsOp() { - return intersectsOp; - } - - /** - * Inserts an item having the given bounds into the tree. - */ - public void insert(Envelope itemEnv, Object item) { - if (itemEnv.isNull()) { return; } - super.insert(itemEnv, item); - } - - /** - * Returns items whose bounds intersect the given envelope. - */ - public List query(Envelope searchEnv) { - //Yes this method does something. It specifies that the bounds is an - //Envelope. super.query takes an Object, not an Envelope. [Jon Aquino 10/24/2003] - return super.query(searchEnv); - } - - /** - * Returns items whose bounds intersect the given envelope. - */ - public void query(Envelope searchEnv, ItemVisitor visitor) { - //Yes this method does something. It specifies that the bounds is an - //Envelope. super.query takes an Object, not an Envelope. [Jon Aquino 10/24/2003] - super.query(searchEnv, visitor); - } - - /** - * Removes a single item from the tree. - * - * @param itemEnv the Envelope of the item to remove - * @param item the item to remove - * @return true if the item was found - */ - public boolean remove(Envelope itemEnv, Object item) { - return super.remove(itemEnv, item); - } - - /** - * Returns the number of items in the tree. - * - * @return the number of items in the tree - */ - public int size() - { - return super.size(); - } - - /** - * Returns the number of items in the tree. - * - * @return the number of items in the tree - */ - public int depth() - { - return super.depth(); - } - - protected Comparator getComparator() { - return yComparator; - } - - /** - * Finds the two nearest items in the tree, - * using {@link ItemDistance} as the distance metric. - * A Branch-and-Bound tree traversal algorithm is used - * to provide an efficient search. - * - * @param itemDist a distance metric applicable to the items in this tree - * @return the pair of the nearest items - */ - public Object[] nearestNeighbour(ItemDistance itemDist) - { - BoundablePair bp = new BoundablePair(this.getRoot(), this.getRoot(), itemDist); - return nearestNeighbour(bp); - } - - /** - * Finds the item in this tree which is nearest to the given {@link Object}, - * using {@link ItemDistance} as the distance metric. - * A Branch-and-Bound tree traversal algorithm is used - * to provide an efficient search. - *

                    - * The query object does not have to be - * contained in the tree, but it does - * have to be compatible with the itemDist - * distance metric. - * - * @param env the envelope of the query item - * @param item the item to find the nearest neighbour of - * @param itemDist a distance metric applicable to the items in this tree and the query item - * @return the nearest item in this tree - */ - public Object nearestNeighbour(Envelope env, Object item, ItemDistance itemDist) - { - Boundable bnd = new ItemBoundable(env, item); - BoundablePair bp = new BoundablePair(this.getRoot(), bnd, itemDist); - return nearestNeighbour(bp)[0]; - } - - - /** - * Finds the item in this tree which is nearest to the given {@link Object}, - * using {@link ItemDistance} as the distance metric. - * A Branch-and-Bound tree traversal algorithm is used - * to provide an efficient search. - *

                    - * The query object does not have to be - * contained in the tree, but it does - * have to be compatible with the itemDist - * distance metric. - * - * @param env the envelope of the query item - * @param item the item to find the nearest neighbour of - * @param itemDist a distance metric applicable to the items in this tree and the query item - * @return the nearest item in this tree - */ - public Envelope[] kNearestNeighbour(Envelope env, Object item, ItemDistance itemDist,int k) - { - Boundable bnd = new ItemBoundable(env, item); - BoundablePair bp = new BoundablePair(this.getRoot(), bnd, itemDist); - return nearestNeighbour(bp,k); - } - /** - * Finds the two nearest items from this tree - * and another tree, - * using {@link ItemDistance} as the distance metric. - * A Branch-and-Bound tree traversal algorithm is used - * to provide an efficient search. - * The result value is a pair of items, - * the first from this tree and the second - * from the argument tree. - * - * @param tree another tree - * @param itemDist a distance metric applicable to the items in the trees - * @return the pair of the nearest items, one from each tree - */ - public Object[] nearestNeighbour(STRtree tree, ItemDistance itemDist) - { - BoundablePair bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist); - return nearestNeighbour(bp); - } - - private Object[] nearestNeighbour(BoundablePair initBndPair) - { - return nearestNeighbour(initBndPair, Double.POSITIVE_INFINITY); - } - private Envelope[] nearestNeighbour(BoundablePair initBndPair, int k) - { - return nearestNeighbour(initBndPair, Double.POSITIVE_INFINITY,k); - } - private Object[] nearestNeighbour(BoundablePair initBndPair, double maxDistance) - { - double distanceLowerBound = maxDistance; - BoundablePair minPair = null; - - // initialize internal structures - PriorityQueue priQ = new PriorityQueue(); - - // initialize queue - priQ.add(initBndPair); - - while (! priQ.isEmpty() && distanceLowerBound > 0.0) { - // pop head of queue and expand one side of pair - BoundablePair bndPair = (BoundablePair) priQ.poll(); - double currentDistance = bndPair.getDistance(); - - /** - * If the distance for the first node in the queue - * is >= the current minimum distance, all other nodes - * in the queue must also have a greater distance. - * So the current minDistance must be the true minimum, - * and we are done. - */ - if (currentDistance >= distanceLowerBound) - break; - - /** - * If the pair members are leaves - * then their distance is the exact lower bound. - * Update the distanceLowerBound to reflect this - * (which must be smaller, due to the test - * immediately prior to this). - */ - if (bndPair.isLeaves()) { - // assert: currentDistance < minimumDistanceFound - distanceLowerBound = currentDistance; - minPair = bndPair; - } - else { - // testing - does allowing a tolerance improve speed? - // Ans: by only about 10% - not enough to matter - /* - double maxDist = bndPair.getMaximumDistance(); - if (maxDist * .99 < lastComputedDistance) - return; - //*/ - - /** - * Otherwise, expand one side of the pair, - * (the choice of which side to expand is heuristically determined) - * and insert the new expanded pairs into the queue - */ - bndPair.expandToQueue(priQ, distanceLowerBound); - } - } - // done - return items with min distance - return new Object[] { - ((ItemBoundable) minPair.getBoundable(0)).getItem(), - ((ItemBoundable) minPair.getBoundable(1)).getItem() - }; - } - - private Envelope[] nearestNeighbour(BoundablePair initBndPair, double maxDistance, int k) - { - double distanceLowerBound = maxDistance; - BoundablePair minPair = null; - - // initialize internal structures - PriorityQueue priQ = new PriorityQueue(); - - // initialize queue - priQ.add(initBndPair); - - List kNearestNeighbors = new ArrayList (); - List kNearestDistances = new ArrayList(); - while (! priQ.isEmpty() && distanceLowerBound >= 0.0) { - // pop head of queue and expand one side of pair - BoundablePair bndPair = (BoundablePair) priQ.poll(); - double currentDistance = bndPair.getDistance(); - - - /** - * If the distance for the first node in the queue - * is >= the current maximum distance in the k queue , all other nodes - * in the queue must also have a greater distance. - * So the current minDistance must be the true minimum, - * and we are done. - */ - - if (currentDistance >= distanceLowerBound && kNearestDistances.size()>=k){ - break; - } - /** - * If the pair members are leaves - * then their distance is the exact lower bound. - * Update the distanceLowerBound to reflect this - * (which must be smaller, due to the test - * immediately prior to this). - */ - if (bndPair.isLeaves()) { - // assert: currentDistance < minimumDistanceFound - - //distanceLowerBound = currentDistance; - if(kNearestDistances.size()>0 && kNearestDistances.size()=k) - { - - if(currentDistancek; - kNearestNeighbors.remove(kNearestNeighbors.size()-1); - kNearestDistances.remove(kNearestDistances.size()-1); - } - } - else if(kNearestDistances.size()==0) - { - kNearestNeighbors.add((Envelope)bndPair.getBoundable(0).getBounds()); - kNearestDistances.add(currentDistance); - } - else - { - try { - throw new Exception("Should never reach here"); - } catch (Exception e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - - - distanceLowerBound = kNearestDistances.get(kNearestDistances.size()-1); - //System.out.println("distanceLowerBound is " + distanceLowerBound); - - - - } - else { - // testing - does allowing a tolerance improve speed? - // Ans: by only about 10% - not enough to matter - /* - double maxDist = bndPair.getMaximumDistance(); - if (maxDist * .99 < lastComputedDistance) - return; - //*/ - - /** - * Otherwise, expand one side of the pair, - * (the choice of which side to expand is heuristically determined) - * and insert the new expanded pairs into the queue - */ - bndPair.expandToQueue(priQ, distanceLowerBound); - } - } - // done - return items with min distance - - return kNearestNeighbors.toArray(new Envelope[kNearestNeighbors.size()]); - } - /** - * This method is to find the boundaries of leaf nodes. - * @return Return the list of boundaries we find. - */ - public List queryBoundary() - { - - return super.queryBoundary(); - - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java b/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java deleted file mode 100644 index d93b8fb42b..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java +++ /dev/null @@ -1,87 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.sweepline; - -/** - * @version 1.7 - */ -public class SweepLineEvent - implements Comparable -{ - public static final int INSERT = 1; - public static final int DELETE = 2; - - private double xValue; - private int eventType; - private SweepLineEvent insertEvent; // null if this is an INSERT event - private int deleteEventIndex; - - SweepLineInterval sweepInt; - public SweepLineEvent(double x, SweepLineEvent insertEvent, SweepLineInterval sweepInt) - { - xValue = x; - this.insertEvent = insertEvent; - this.eventType = INSERT; - if (insertEvent != null) - eventType = DELETE; - this.sweepInt = sweepInt; - } - - public boolean isInsert() { return insertEvent == null; } - public boolean isDelete() { return insertEvent != null; } - public SweepLineEvent getInsertEvent() { return insertEvent; } - public int getDeleteEventIndex() { return deleteEventIndex; } - public void setDeleteEventIndex(int deleteEventIndex) { this.deleteEventIndex = deleteEventIndex; } - - SweepLineInterval getInterval() { return sweepInt; } - - /** - * ProjectionEvents are ordered first by their x-value, and then by their eventType. - * It is important that Insert events are sorted before Delete events, so that - * items whose Insert and Delete events occur at the same x-value will be - * correctly handled. - */ - public int compareTo(Object o) { - SweepLineEvent pe = (SweepLineEvent) o; - if (xValue < pe.xValue) return -1; - if (xValue > pe.xValue) return 1; - if (eventType < pe.eventType) return -1; - if (eventType > pe.eventType) return 1; - return 0; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java b/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java deleted file mode 100644 index 762fcd0cf0..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java +++ /dev/null @@ -1,114 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.sweepline; - -import java.util.*; - -/** - * A sweepline implements a sorted index on a set of intervals. - * It is used to compute all overlaps between the interval in the index. - * - * @version 1.7 - */ -public class SweepLineIndex { - - List events = new ArrayList(); - private boolean indexBuilt; - // statistics information - private int nOverlaps; - - public SweepLineIndex() { - } - - public void add(SweepLineInterval sweepInt) - { - SweepLineEvent insertEvent = new SweepLineEvent(sweepInt.getMin(), null, sweepInt); - events.add(insertEvent); - events.add(new SweepLineEvent(sweepInt.getMax(), insertEvent, sweepInt)); - } - - /** - * Because Delete Events have a link to their corresponding Insert event, - * it is possible to compute exactly the range of events which must be - * compared to a given Insert event object. - */ - private void buildIndex() - { - if (indexBuilt) return; - Collections.sort(events); - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isDelete()) { - ev.getInsertEvent().setDeleteEventIndex(i); - } - } - indexBuilt = true; - } - - public void computeOverlaps(SweepLineOverlapAction action) - { - nOverlaps = 0; - buildIndex(); - - for (int i = 0; i < events.size(); i++ ) - { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isInsert()) { - processOverlaps(i, ev.getDeleteEventIndex(), ev.getInterval(), action); - } - } - } - - private void processOverlaps(int start, int end, SweepLineInterval s0, SweepLineOverlapAction action) - { - /** - * Since we might need to test for self-intersections, - * include current insert event object in list of event objects to test. - * Last index can be skipped, because it must be a Delete event. - */ - for (int i = start; i < end; i++ ) { - SweepLineEvent ev = (SweepLineEvent) events.get(i); - if (ev.isInsert()) { - SweepLineInterval s1 = ev.getInterval(); - action.overlap(s0, s1); - nOverlaps++; - } - } - - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java b/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java deleted file mode 100644 index 2fd92490e4..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java +++ /dev/null @@ -1,61 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.sweepline; - -/** - * @version 1.7 - */ -public class SweepLineInterval { - - private double min, max; - private Object item; - - public SweepLineInterval(double min, double max) - { - this(min, max, null); - } - - public SweepLineInterval(double min, double max, Object item) - { - this.min = min < max ? min : max; - this.max = max > min ? max : min; - this.item = item; - } - - public double getMin() { return min; } - public double getMax() { return max; } - public Object getItem() { return item; } - -} diff --git a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java b/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java deleted file mode 100644 index 5591eef897..0000000000 --- a/src/main/java/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java +++ /dev/null @@ -1,46 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.index.sweepline; - -/** - * An action taken when a {@link SweepLineIndex} detects that two - * {@link SweepLineInterval}s overlap - * - * @version 1.7 - */ -public interface SweepLineOverlapAction { - - void overlap(SweepLineInterval s0, SweepLineInterval s1); -} diff --git a/src/main/java/com/vividsolutions/jts/io/ByteArrayInStream.java b/src/main/java/com/vividsolutions/jts/io/ByteArrayInStream.java deleted file mode 100644 index 2db866ad0b..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/ByteArrayInStream.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -/** - * Allows an array of bytes to be used as an {@link InStream}. - * To optimize memory usage, instances can be reused - * with different byte arrays. - */ -public class ByteArrayInStream - implements InStream -{ - /* - * Implementation improvement suggested by Andrea Aime - Dec 15 2007 - */ - - private byte[] buffer; - private int position; - - /** - * Creates a new stream based on the given buffer. - * - * @param buffer the bytes to read - */ - public ByteArrayInStream(final byte[] buffer) { - setBytes(buffer); - } - - /** - * Sets this stream to read from the given buffer - * - * @param buffer the bytes to read - */ - public void setBytes(final byte[] buffer) { - this.buffer = buffer; - this.position = 0; - } - - /** - * Reads up to buf.length bytes from the stream - * into the given byte buffer. - * - * @param buf the buffer to place the read bytes into - */ - public void read(final byte[] buf) { - int numToRead = buf.length; - // don't try and copy past the end of the input - if ((position + numToRead) > buffer.length) { - numToRead = buffer.length - position; - System.arraycopy(buffer, position, buf, 0, numToRead); - // zero out the unread bytes - for (int i = numToRead; i < buf.length; i++) { - buf[i] = 0; - } - } - else { - System.arraycopy(buffer, position, buf, 0, numToRead); - } - position += numToRead; - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/ByteOrderDataInStream.java b/src/main/java/com/vividsolutions/jts/io/ByteOrderDataInStream.java deleted file mode 100644 index 57c945a437..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/ByteOrderDataInStream.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.IOException; - -/** - * Allows reading a stream of Java primitive datatypes from an underlying - * {@link InStream}, - * with the representation being in either common byte ordering. - */ -public class ByteOrderDataInStream -{ - private int byteOrder = ByteOrderValues.BIG_ENDIAN; - private InStream stream; - // buffers to hold primitive datatypes - private byte[] buf1 = new byte[1]; - private byte[] buf4 = new byte[4]; - private byte[] buf8 = new byte[8]; - - public ByteOrderDataInStream() - { - this.stream = null; - } - - public ByteOrderDataInStream(InStream stream) - { - this.stream = stream; - } - - /** - * Allows a single ByteOrderDataInStream to be reused - * on multiple InStreams. - * - * @param stream - */ - public void setInStream(InStream stream) - { - this.stream = stream; - } - public void setOrder(int byteOrder) - { - this.byteOrder = byteOrder; - } - - /** - * Reads a byte value - * - * @return the byte read - */ - public byte readByte() - throws IOException - { - stream.read(buf1); - return buf1[0]; - } - - public int readInt() - throws IOException - { - stream.read(buf4); - return ByteOrderValues.getInt(buf4, byteOrder); - } - public long readLong() - throws IOException - { - stream.read(buf8); - return ByteOrderValues.getLong(buf8, byteOrder); - } - - public double readDouble() - throws IOException - { - stream.read(buf8); - return ByteOrderValues.getDouble(buf8, byteOrder); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/io/ByteOrderValues.java b/src/main/java/com/vividsolutions/jts/io/ByteOrderValues.java deleted file mode 100644 index df3cd4d27a..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/ByteOrderValues.java +++ /dev/null @@ -1,139 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -/** - * Methods to read and write primitive Java datatypes from/to byte - * sequences, allowing the byte order to be specified - *

                    - * Similar to the standard Java ByteBuffer class. - */ -public class ByteOrderValues -{ - public static final int BIG_ENDIAN = 1; - public static final int LITTLE_ENDIAN = 2; - - public static int getInt(byte[] buf, int byteOrder) - { - if (byteOrder == BIG_ENDIAN) { - return ( (int) (buf[0] & 0xff) << 24) - | ( (int) (buf[1] & 0xff) << 16) - | ( (int) (buf[2] & 0xff) << 8) - | (( int) (buf[3] & 0xff) ); - } - else {// LITTLE_ENDIAN - return ( (int) (buf[3] & 0xff) << 24) - | ( (int) (buf[2] & 0xff) << 16) - | ( (int) (buf[1] & 0xff) << 8) - | ( (int) (buf[0] & 0xff) ); - } - } - - public static void putInt(int intValue, byte[] buf, int byteOrder) - { - if (byteOrder == BIG_ENDIAN) { - buf[0] = (byte)(intValue >> 24); - buf[1] = (byte)(intValue >> 16); - buf[2] = (byte)(intValue >> 8); - buf[3] = (byte) intValue; - } - else {// LITTLE_ENDIAN - buf[0] = (byte) intValue; - buf[1] = (byte)(intValue >> 8); - buf[2] = (byte)(intValue >> 16); - buf[3] = (byte)(intValue >> 24); - } - } - public static long getLong(byte[] buf, int byteOrder) - { - if (byteOrder == BIG_ENDIAN) { - return - (long) (buf[0] & 0xff) << 56 - | (long) (buf[1] & 0xff) << 48 - | (long) (buf[2] & 0xff) << 40 - | (long) (buf[3] & 0xff) << 32 - | (long) (buf[4] & 0xff) << 24 - | (long) (buf[5] & 0xff) << 16 - | (long) (buf[6] & 0xff) << 8 - | (long) (buf[7] & 0xff); - } - else {// LITTLE_ENDIAN - return - (long) (buf[7] & 0xff) << 56 - | (long) (buf[6] & 0xff) << 48 - | (long) (buf[5] & 0xff) << 40 - | (long) (buf[4] & 0xff) << 32 - | (long) (buf[3] & 0xff) << 24 - | (long) (buf[2] & 0xff) << 16 - | (long) (buf[1] & 0xff) << 8 - | (long) (buf[0] & 0xff); - } - } - - public static void putLong(long longValue, byte[] buf, int byteOrder) - { - if (byteOrder == BIG_ENDIAN) { - buf[0] = (byte)(longValue >> 56); - buf[1] = (byte)(longValue >> 48); - buf[2] = (byte)(longValue >> 40); - buf[3] = (byte)(longValue >> 32); - buf[4] = (byte)(longValue >> 24); - buf[5] = (byte)(longValue >> 16); - buf[6] = (byte)(longValue >> 8); - buf[7] = (byte) longValue; - } - else { // LITTLE_ENDIAN - buf[0] = (byte) longValue; - buf[1] = (byte)(longValue >> 8); - buf[2] = (byte)(longValue >> 16); - buf[3] = (byte)(longValue >> 24); - buf[4] = (byte)(longValue >> 32); - buf[5] = (byte)(longValue >> 40); - buf[6] = (byte)(longValue >> 48); - buf[7] = (byte)(longValue >> 56); - } - } - - public static double getDouble(byte[] buf, int byteOrder) - { - long longVal = getLong(buf, byteOrder); - return Double.longBitsToDouble(longVal); - } - - public static void putDouble(double doubleValue, byte[] buf, int byteOrder) - { - long longVal = Double.doubleToLongBits(doubleValue); - putLong(longVal, buf, byteOrder); - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/io/InStream.java b/src/main/java/com/vividsolutions/jts/io/InStream.java deleted file mode 100644 index 1fadb99814..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/InStream.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.IOException; - -/** - * A interface for classes providing an input stream of bytes. - * This interface is similar to the Java InputStream, - * but with a narrower interface to make it easier to implement. - * - */ -public interface InStream -{ - /** - * Reads buf.length bytes from the input stream - * and stores them in the supplied buffer. - * - * @param buf the buffer to receive the bytes - * - * @throws IOException if an I/O error occurs - */ - void read(byte[] buf) throws IOException; -} diff --git a/src/main/java/com/vividsolutions/jts/io/InputStreamInStream.java b/src/main/java/com/vividsolutions/jts/io/InputStreamInStream.java deleted file mode 100644 index dc5745dbe9..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/InputStreamInStream.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.*; - -/** - * An adapter to allow an {@link InputStream} to be used as an {@link InStream} - */ -public class InputStreamInStream - implements InStream -{ - private InputStream is; - - public InputStreamInStream(InputStream is) - { - this.is = is; - } - - public void read(byte[] buf) throws IOException - { - is.read(buf); - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/OutStream.java b/src/main/java/com/vividsolutions/jts/io/OutStream.java deleted file mode 100644 index 0b2bd3bb35..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/OutStream.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.IOException; - -/** - * A interface for classes providing an output stream of bytes. - * This interface is similar to the Java OutputStream, - * but with a narrower interface to make it easier to implement. - */ -public interface OutStream -{ - void write(byte[] buf, int len) throws IOException; -} diff --git a/src/main/java/com/vividsolutions/jts/io/OutputStreamOutStream.java b/src/main/java/com/vividsolutions/jts/io/OutputStreamOutStream.java deleted file mode 100644 index 63becb6443..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/OutputStreamOutStream.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * An adapter to allow an {@link OutputStream} to be used as an {@link OutStream} - */ -public class OutputStreamOutStream - implements OutStream -{ - private OutputStream os; - - public OutputStreamOutStream(OutputStream os) - { - this.os = os; - } - public void write(byte[] buf, int len) throws IOException - { - os.write(buf, 0, len); - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/ParseException.java b/src/main/java/com/vividsolutions/jts/io/ParseException.java deleted file mode 100644 index c143071506..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/ParseException.java +++ /dev/null @@ -1,75 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -/** - * Thrown by a WKTReader when a parsing problem occurs. - * - *@version 1.7 - */ -public class ParseException extends Exception { - - /** - * Creates a ParseException with the given detail message. - * - *@param message a description of this ParseException - */ - public ParseException(String message) { - super(message); - } - - /** - * Creates a ParseException with es detail message. - * - *@param e an exception that occurred while a WKTReader was - * parsing a Well-known Text string - */ - public ParseException(Exception e) { - this(e.toString(), e); - } - - /** - * Creates a ParseException with es detail message. - * - *@param message a description of this ParseException - *@param e a throwable that occurred while a com.vividsolutions.jts.io reader was - * parsing a string representation - */ - public ParseException(String message, Throwable e) { - super(message, e); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/io/WKBConstants.java b/src/main/java/com/vividsolutions/jts/io/WKBConstants.java deleted file mode 100644 index ecfe87a001..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKBConstants.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -/** - * Constant values used by the WKB format - */ -public interface WKBConstants { - int wkbXDR = 0; - int wkbNDR = 1; - - int wkbPoint = 1; - int wkbLineString = 2; - int wkbPolygon = 3; - int wkbMultiPoint = 4; - int wkbMultiLineString = 5; - int wkbMultiPolygon = 6; - int wkbGeometryCollection = 7; -} diff --git a/src/main/java/com/vividsolutions/jts/io/WKBHexFileReader.java b/src/main/java/com/vividsolutions/jts/io/WKBHexFileReader.java deleted file mode 100644 index 70aaa59d74..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKBHexFileReader.java +++ /dev/null @@ -1,185 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.io; - -import java.io.*; -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Reads a sequence of {@link Geometry}s in WKBHex format - * from a text file. - * Each WKBHex geometry must be on a single line - * The geometries in the file may be separated by any amount - * of whitespace and newlines. - * - * @author Martin Davis - * - */ -public class WKBHexFileReader -{ - private File file = null; - private Reader reader; - private WKBReader wkbReader; - private int count = 0; - private int limit = -1; - private int offset = 0; - - /** - * Creates a new WKBHexFileReader given the File to read from - * and a WKTReader to use to parse the geometries. - * - * @param file the File to read from - * @param wkbReader the geometry reader to use - */ - public WKBHexFileReader(File file, WKBReader wkbReader) - { - this.file = file; - this.wkbReader = wkbReader; - } - - /** - * Creates a new WKBHexFileReader, given the name of the file to read from. - * - * @param filename the name of the file to read from - * @param wkbReader the geometry reader to use - */ - public WKBHexFileReader(String filename, WKBReader wkbReader) - { - this(new File(filename), wkbReader); - } - - /** - * Creates a new WKBHexFileReader, given a {@link Reader} to read from. - * - * @param reader the reader to read from - * @param wkbReader the geometry reader to use - */ - public WKBHexFileReader(Reader reader, WKBReader wkbReader) - { - this.reader = reader; - this.wkbReader = wkbReader; - } - - /** - * Sets the maximum number of geometries to read. - * - * @param limit the maximum number of geometries to read - */ - public void setLimit(int limit) - { - this.limit = limit; - } - - /** - * Sets the number of geometries to skip before storing. - * - * @param offset the number of geometries to skip - */ - public void setOffset(int offset) - { - this.offset = offset; - } - - /** - * Reads a sequence of geometries. - * If an offset is specified, geometries read up to the offset count are skipped. - * If a limit is specified, no more than limit geometries are read. - * - * @return the list of geometries read - * @throws IOException if an I/O exception was encountered - * @throws ParseException if an error occured reading a geometry - */ - public List read() - throws IOException, ParseException - { - // do this here so that constructors don't throw exceptions - if (file != null) - reader = new FileReader(file); - - count = 0; - try { - BufferedReader bufferedReader = new BufferedReader(reader); - try { - return read(bufferedReader); - } finally { - bufferedReader.close(); - } - } finally { - reader.close(); - } - } - - private List read(BufferedReader bufferedReader) throws IOException, - ParseException { - List geoms = new ArrayList(); - while (! isAtEndOfFile(bufferedReader) && ! isAtLimit(geoms)) { - String line = bufferedReader.readLine().trim(); - if (line.length() == 0) - continue; - Geometry g = wkbReader.read(WKBReader.hexToBytes(line)); - if (count >= offset) - geoms.add(g); - count++; - } - return geoms; - } - - private boolean isAtLimit(List geoms) - { - if (limit < 0) return false; - if (geoms.size() < limit) return false; - return true; - } - - private static final int MAX_LOOKAHEAD = 1000; - - /** - * Tests if reader is at EOF. - */ - private boolean isAtEndOfFile(BufferedReader bufferedReader) - throws IOException - { - bufferedReader.mark(MAX_LOOKAHEAD); - - StreamTokenizer tokenizer = new StreamTokenizer(bufferedReader); - int type = tokenizer.nextToken(); - - if (type == StreamTokenizer.TT_EOF) { - return true; - } - bufferedReader.reset(); - return false; - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/WKBReader.java b/src/main/java/com/vividsolutions/jts/io/WKBReader.java deleted file mode 100644 index 047ade3296..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKBReader.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.IOException; -import com.vividsolutions.jts.geom.*; - -/** - * Reads a {@link Geometry}from a byte stream in Well-Known Binary format. - * Supports use of an {@link InStream}, which allows easy use - * with arbitrary byte stream sources. - *

                    - * This class reads the format describe in {@link WKBWriter}. - * It also partially handles - * the Extended WKB format used by PostGIS, - * by parsing and storing SRID values. - * The reader repairs structurally-invalid input - * (specifically, LineStrings and LinearRings which contain - * too few points have vertices added, - * and non-closed rings are closed). - *

                    - * This class is designed to support reuse of a single instance to read multiple - * geometries. This class is not thread-safe; each thread should create its own - * instance. - * - * @see WKBWriter for a formal format specification - */ -public class WKBReader -{ - /** - * Converts a hexadecimal string to a byte array. - * The hexadecimal digit symbols are case-insensitive. - * - * @param hex a string containing hex digits - * @return an array of bytes with the value of the hex string - */ - public static byte[] hexToBytes(String hex) - { - int byteLen = hex.length() / 2; - byte[] bytes = new byte[byteLen]; - - for (int i = 0; i < hex.length() / 2; i++) { - int i2 = 2 * i; - if (i2 + 1 > hex.length()) - throw new IllegalArgumentException("Hex string has odd length"); - - int nib1 = hexToInt(hex.charAt(i2)); - int nib0 = hexToInt(hex.charAt(i2 + 1)); - byte b = (byte) ((nib1 << 4) + (byte) nib0); - bytes[i] = b; - } - return bytes; - } - - private static int hexToInt(char hex) - { - int nib = Character.digit(hex, 16); - if (nib < 0) - throw new IllegalArgumentException("Invalid hex digit: '" + hex + "'"); - return nib; - } - - private static final String INVALID_GEOM_TYPE_MSG - = "Invalid geometry type encountered in "; - - private GeometryFactory factory; - private CoordinateSequenceFactory csFactory; - private PrecisionModel precisionModel; - // default dimension - will be set on read - private int inputDimension = 2; - private boolean hasSRID = false; - private int SRID = 0; - /** - * true if structurally invalid input should be reported rather than repaired. - * At some point this could be made client-controllable. - */ - private boolean isStrict = false; - private ByteOrderDataInStream dis = new ByteOrderDataInStream(); - private double[] ordValues; - - public WKBReader() { - this(new GeometryFactory()); - } - - public WKBReader(GeometryFactory geometryFactory) { - this.factory = geometryFactory; - precisionModel = factory.getPrecisionModel(); - csFactory = factory.getCoordinateSequenceFactory(); - } - - /** - * Reads a single {@link Geometry} in WKB format from a byte array. - * - * @param bytes the byte array to read from - * @return the geometry read - * @throws ParseException if the WKB is ill-formed - */ - public Geometry read(byte[] bytes) throws ParseException - { - // possibly reuse the ByteArrayInStream? - // don't throw IOExceptions, since we are not doing any I/O - try { - return read(new ByteArrayInStream(bytes)); - } - catch (IOException ex) { - throw new RuntimeException("Unexpected IOException caught: " + ex.getMessage()); - } - } - - /** - * Reads a {@link Geometry} in binary WKB format from an {@link InStream}. - * - * @param is the stream to read from - * @return the Geometry read - * @throws IOException if the underlying stream creates an error - * @throws ParseException if the WKB is ill-formed - */ - public Geometry read(InStream is) - throws IOException, ParseException - { - dis.setInStream(is); - Geometry g = readGeometry(); - return g; - } - - private Geometry readGeometry() - throws IOException, ParseException - { - - // determine byte order - byte byteOrderWKB = dis.readByte(); - - // always set byte order, since it may change from geometry to geometry - if(byteOrderWKB == WKBConstants.wkbNDR) - { - dis.setOrder(ByteOrderValues.LITTLE_ENDIAN); - } - else if(byteOrderWKB == WKBConstants.wkbXDR) - { - dis.setOrder(ByteOrderValues.BIG_ENDIAN); - } - else if(isStrict) - { - throw new ParseException("Unknown geometry byte order (not NDR or XDR): " + byteOrderWKB); - } - //if not strict and not XDR or NDR, then we just use the dis default set at the - //start of the geometry (if a multi-geometry). This allows WBKReader to work - //with Spatialite native BLOB WKB, as well as other WKB variants that might just - //specify endian-ness at the start of the multigeometry. - - - int typeInt = dis.readInt(); - int geometryType = typeInt & 0xff; - // determine if Z values are present - boolean hasZ = (typeInt & 0x80000000) != 0; - inputDimension = hasZ ? 3 : 2; - // determine if SRIDs are present - hasSRID = (typeInt & 0x20000000) != 0; - - int SRID = 0; - if (hasSRID) { - SRID = dis.readInt(); - } - - // only allocate ordValues buffer if necessary - if (ordValues == null || ordValues.length < inputDimension) - ordValues = new double[inputDimension]; - - Geometry geom = null; - switch (geometryType) { - case WKBConstants.wkbPoint : - geom = readPoint(); - break; - case WKBConstants.wkbLineString : - geom = readLineString(); - break; - case WKBConstants.wkbPolygon : - geom = readPolygon(); - break; - case WKBConstants.wkbMultiPoint : - geom = readMultiPoint(); - break; - case WKBConstants.wkbMultiLineString : - geom = readMultiLineString(); - break; - case WKBConstants.wkbMultiPolygon : - geom = readMultiPolygon(); - break; - case WKBConstants.wkbGeometryCollection : - geom = readGeometryCollection(); - break; - default: - throw new ParseException("Unknown WKB type " + geometryType); - } - setSRID(geom, SRID); - return geom; - } - - /** - * Sets the SRID, if it was specified in the WKB - * - * @param g the geometry to update - * @return the geometry with an updated SRID value, if required - */ - private Geometry setSRID(Geometry g, int SRID) - { - if (SRID != 0) - g.setSRID(SRID); - return g; - } - - private Point readPoint() throws IOException - { - CoordinateSequence pts = readCoordinateSequence(1); - return factory.createPoint(pts); - } - - private LineString readLineString() throws IOException - { - int size = dis.readInt(); - CoordinateSequence pts = readCoordinateSequenceLineString(size); - return factory.createLineString(pts); - } - - private LinearRing readLinearRing() throws IOException - { - int size = dis.readInt(); - CoordinateSequence pts = readCoordinateSequenceRing(size); - return factory.createLinearRing(pts); - } - - private Polygon readPolygon() throws IOException - { - int numRings = dis.readInt(); - LinearRing[] holes = null; - if (numRings > 1) - holes = new LinearRing[numRings - 1]; - - LinearRing shell = readLinearRing(); - for (int i = 0; i < numRings - 1; i++) { - holes[i] = readLinearRing(); - } - return factory.createPolygon(shell, holes); - } - - private MultiPoint readMultiPoint() throws IOException, ParseException - { - int numGeom = dis.readInt(); - Point[] geoms = new Point[numGeom]; - for (int i = 0; i < numGeom; i++) { - Geometry g = readGeometry(); - if (! (g instanceof Point)) - throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiPoint"); - geoms[i] = (Point) g; - } - return factory.createMultiPoint(geoms); - } - - private MultiLineString readMultiLineString() throws IOException, ParseException - { - int numGeom = dis.readInt(); - LineString[] geoms = new LineString[numGeom]; - for (int i = 0; i < numGeom; i++) { - Geometry g = readGeometry(); - if (! (g instanceof LineString)) - throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiLineString"); - geoms[i] = (LineString) g; - } - return factory.createMultiLineString(geoms); - } - - private MultiPolygon readMultiPolygon() throws IOException, ParseException - { - int numGeom = dis.readInt(); - Polygon[] geoms = new Polygon[numGeom]; - - for (int i = 0; i < numGeom; i++) { - Geometry g = readGeometry(); - if (! (g instanceof Polygon)) - throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiPolygon"); - geoms[i] = (Polygon) g; - } - return factory.createMultiPolygon(geoms); - } - - private GeometryCollection readGeometryCollection() throws IOException, ParseException - { - int numGeom = dis.readInt(); - Geometry[] geoms = new Geometry[numGeom]; - for (int i = 0; i < numGeom; i++) { - geoms[i] = readGeometry(); - } - return factory.createGeometryCollection(geoms); - } - - private CoordinateSequence readCoordinateSequence(int size) throws IOException - { - CoordinateSequence seq = csFactory.create(size, inputDimension); - int targetDim = seq.getDimension(); - if (targetDim > inputDimension) - targetDim = inputDimension; - for (int i = 0; i < size; i++) { - readCoordinate(); - for (int j = 0; j < targetDim; j++) { - seq.setOrdinate(i, j, ordValues[j]); - } - } - return seq; - } - - private CoordinateSequence readCoordinateSequenceLineString(int size) throws IOException - { - CoordinateSequence seq = readCoordinateSequence(size); - if (isStrict) return seq; - if (seq.size() == 0 || seq.size() >= 2) return seq; - return CoordinateSequences.extend(csFactory, seq, 2); - } - - private CoordinateSequence readCoordinateSequenceRing(int size) throws IOException - { - CoordinateSequence seq = readCoordinateSequence(size); - if (isStrict) return seq; - if (CoordinateSequences.isRing(seq)) return seq; - return CoordinateSequences.ensureValidRing(csFactory, seq); - } - - /** - * Reads a coordinate value with the specified dimensionality. - * Makes the X and Y ordinates precise according to the precision model - * in use. - */ - private void readCoordinate() throws IOException - { - for (int i = 0; i < inputDimension; i++) { - if (i <= 1) { - ordValues[i] = precisionModel.makePrecise(dis.readDouble()); - } - else { - ordValues[i] = dis.readDouble(); - } - - } - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/io/WKBWriter.java b/src/main/java/com/vividsolutions/jts/io/WKBWriter.java deleted file mode 100644 index 6e2e2bc8df..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKBWriter.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import java.io.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Writes a {@link Geometry} into Well-Known Binary format. - * Supports use of an {@link OutStream}, which allows easy use - * with arbitary byte stream sinks. - *

                    - * The WKB format is specified in the - * OGC Simple Features for SQL - * specification. - * This implementation also supports the Extended WKB - * standard. Extended WKB allows writing 3-dimensional coordinates - * and including the geometry SRID value. - * The presence of 3D coordinates is signified - * by setting the high bit of the wkbType word. - * The presence of an SRID is signified - * by setting the third bit of the wkbType word. - * EWKB format is upward compatible with the original SFS WKB format. - *

                    - * Empty Points cannot be represented in WKB; an - * {@link IllegalArgumentException} will be thrown if one is - * written. - *

                    - * The WKB specification does not support representing {@link LinearRing}s; - * they will be written as {@link LineString}s. - *

                    - * This class is designed to support reuse of a single instance to read multiple - * geometries. This class is not thread-safe; each thread should create its own - * instance. - * - *

                    Syntax

                    - * The following syntax specification describes the version of Well-Known Binary - * supported by JTS. - *

                    - * The specification uses a syntax language similar to that used in - * the C language. Bitfields are specified from hi-order to lo-order bits. - *

                    - *

                    - * 
                    - * byte = 1 byte
                    - * uint32 = 32 bit unsigned integer (4 bytes)
                    - * double = double precision number (8 bytes)
                    - * 
                    - * abstract Point { }
                    - * 
                    - * Point2D extends Point {
                    - * 	double x;
                    - * 	double y;
                    - * }
                    - * 
                    - * Point3D extends Point {
                    - * 	double x;
                    - * 	double y;
                    - * 	double z;
                    - * }
                    - * 
                    - * LinearRing {
                    - * 	uint32 numPoints;
                    - * 	Point points[numPoints];
                    - * }
                    - * 
                    - * enum wkbGeometryType {
                    - * 	wkbPoint = 1,
                    - * 	wkbLineString = 2,
                    - * 	wkbPolygon = 3,
                    - * 	wkbMultiPoint = 4,
                    - * 	wkbMultiLineString = 5,
                    - * 	wkbMultiPolygon = 6,
                    - * 	wkbGeometryCollection = 7
                    - * }
                    - * 
                    - * enum byteOrder {
                    - * 	wkbXDR = 0,	// Big Endian
                    - * 	wkbNDR = 1 	// Little Endian
                    - * }
                    - * 
                    - * WKBType {
                    - * 	uint32 wkbGeometryType : 8; // values from enum wkbGeometryType
                    - * }
                    - * 
                    - * EWKBType {
                    - * 	uint32 is3D : 1; 	// 0 = 2D, 1 = 3D
                    - * 	uint32 noData1 : 1; 
                    - * 	uint32 hasSRID : 1;  	// 0, no, 1 = yes
                    - * 	uint32 noData2 : 21; 
                    - * 	uint32 wkbGeometryType : 8; // values from enum wkbGeometryType
                    - * }
                    - * 
                    - * abstract WKBGeometry {
                    - * 	byte byteOrder;		// values from enum byteOrder
                    - * 	EWKBType wkbType
                    - * 	[ uint32 srid; ] 	// only if hasSRID = yes
                    - * }
                    - * 
                    - * WKBPoint extends WKBGeometry {
                    - * 	Point point;
                    - * }
                    - * 
                    - * WKBLineString extends WKBGeometry {
                    - * 	uint32 numCoords;
                    - * 	Point points[numCoords];
                    - * }
                    - * 
                    - * WKBPolygon extends WKBGeometry {
                    - * 	uint32 numRings;
                    - * 	LinearRing rings[numRings];
                    - * }
                    - * 
                    - * WKBMultiPoint extends WKBGeometry {
                    - * 	uint32 numElems;
                    - * 	WKBPoint elems[numElems];
                    - * }
                    - * 
                    - * WKBMultiLineString extends WKBGeometry {
                    - * 	uint32 numElems;
                    - * 	WKBLineString elems[numElems];
                    - * }
                    - * 
                    - * wkbMultiPolygon extends WKBGeometry {
                    - * 	uint32 numElems;
                    - * 	WKBPolygon elems[numElems];
                    - * }
                    - * 
                    - * WKBGeometryCollection extends WKBGeometry {
                    - * 	uint32 numElems;
                    - * 	WKBGeometry elems[numElems];
                    - * }
                    - * 
                    - * 
                    - * @see WKBReader - */ -public class WKBWriter -{ - /** - * Converts a byte array to a hexadecimal string. - * - * @param bytes - * @return a string of hexadecimal digits - * - * @deprecated - */ - public static String bytesToHex(byte[] bytes) - { - return toHex(bytes); - } - - /** - * Converts a byte array to a hexadecimal string. - * - * @param bytes a byte array - * @return a string of hexadecimal digits - */ - public static String toHex(byte[] bytes) - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; - buf.append(toHexDigit((b >> 4) & 0x0F)); - buf.append(toHexDigit(b & 0x0F)); - } - return buf.toString(); - } - - private static char toHexDigit(int n) - { - if (n < 0 || n > 15) - throw new IllegalArgumentException("Nibble value out of range: " + n); - if (n <= 9) - return (char) ('0' + n); - return (char) ('A' + (n - 10)); - } - - private int outputDimension = 2; - private int byteOrder; - private boolean includeSRID = false; - private ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); - private OutStream byteArrayOutStream = new OutputStreamOutStream(byteArrayOS); - // holds output data values - private byte[] buf = new byte[8]; - - /** - * Creates a writer that writes {@link Geometry}s with - * output dimension = 2 and BIG_ENDIAN byte order - */ - public WKBWriter() { - this(2, ByteOrderValues.BIG_ENDIAN); - } - - /** - * Creates a writer that writes {@link Geometry}s with - * the given dimension (2 or 3) for output coordinates - * and {@link ByteOrderValues#BIG_ENDIAN} byte order. - * If the input geometry has a small coordinate dimension, - * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}. - * - * @param outputDimension the coordinate dimension to output (2 or 3) - */ - public WKBWriter(int outputDimension) { - this(outputDimension, ByteOrderValues.BIG_ENDIAN); - } - - /** - * Creates a writer that writes {@link Geometry}s with - * the given dimension (2 or 3) for output coordinates - * and {@link ByteOrderValues#BIG_ENDIAN} byte order. This constructor also - * takes a flag to control whether srid information will be - * written. - * If the input geometry has a smaller coordinate dimension, - * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}. - * - * @param outputDimension the coordinate dimension to output (2 or 3) - * @param includeSRID indicates whether SRID should be written - */ - public WKBWriter(int outputDimension, boolean includeSRID) { - this(outputDimension, ByteOrderValues.BIG_ENDIAN, includeSRID); - } - - /** - * Creates a writer that writes {@link Geometry}s with - * the given dimension (2 or 3) for output coordinates - * and byte order - * If the input geometry has a small coordinate dimension, - * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}. - * - * @param outputDimension the coordinate dimension to output (2 or 3) - * @param byteOrder the byte ordering to use - */ - public WKBWriter(int outputDimension, int byteOrder) { - this(outputDimension, byteOrder, false); - } - - /** - * Creates a writer that writes {@link Geometry}s with - * the given dimension (2 or 3) for output coordinates - * and byte order. This constructor also takes a flag to - * control whether srid information will be written. - * If the input geometry has a small coordinate dimension, - * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}. - * - * @param outputDimension the coordinate dimension to output (2 or 3) - * @param byteOrder the byte ordering to use - * @param includeSRID indicates whether SRID should be written - */ - public WKBWriter(int outputDimension, int byteOrder, boolean includeSRID) { - this.outputDimension = outputDimension; - this.byteOrder = byteOrder; - this.includeSRID = includeSRID; - - if (outputDimension < 2 || outputDimension > 3) - throw new IllegalArgumentException("Output dimension must be 2 or 3"); - } - - /** - * Writes a {@link Geometry} into a byte array. - * - * @param geom the geometry to write - * @return the byte array containing the WKB - */ - public byte[] write(Geometry geom) - { - try { - byteArrayOS.reset(); - write(geom, byteArrayOutStream); - } - catch (IOException ex) { - throw new RuntimeException("Unexpected IO exception: " + ex.getMessage()); - } - return byteArrayOS.toByteArray(); - } - - /** - * Writes a {@link Geometry} to an {@link OutStream}. - * - * @param geom the geometry to write - * @param os the out stream to write to - * @throws IOException if an I/O error occurs - */ - public void write(Geometry geom, OutStream os) throws IOException - { - if (geom instanceof Point) - writePoint((Point) geom, os); - // LinearRings will be written as LineStrings - else if (geom instanceof LineString) - writeLineString((LineString) geom, os); - else if (geom instanceof Polygon) - writePolygon((Polygon) geom, os); - else if (geom instanceof MultiPoint) - writeGeometryCollection(WKBConstants.wkbMultiPoint, - (MultiPoint) geom, os); - else if (geom instanceof MultiLineString) - writeGeometryCollection(WKBConstants.wkbMultiLineString, - (MultiLineString) geom, os); - else if (geom instanceof MultiPolygon) - writeGeometryCollection(WKBConstants.wkbMultiPolygon, - (MultiPolygon) geom, os); - else if (geom instanceof GeometryCollection) - writeGeometryCollection(WKBConstants.wkbGeometryCollection, - (GeometryCollection) geom, os); - else { - Assert.shouldNeverReachHere("Unknown Geometry type"); - } - } - - private void writePoint(Point pt, OutStream os) throws IOException - { - if (pt.getCoordinateSequence().size() == 0) - throw new IllegalArgumentException("Empty Points cannot be represented in WKB"); - writeByteOrder(os); - writeGeometryType(WKBConstants.wkbPoint, pt, os); - writeCoordinateSequence(pt.getCoordinateSequence(), false, os); - } - - private void writeLineString(LineString line, OutStream os) - throws IOException - { - writeByteOrder(os); - writeGeometryType(WKBConstants.wkbLineString, line, os); - writeCoordinateSequence(line.getCoordinateSequence(), true, os); - } - - private void writePolygon(Polygon poly, OutStream os) throws IOException - { - writeByteOrder(os); - writeGeometryType(WKBConstants.wkbPolygon, poly, os); - writeInt(poly.getNumInteriorRing() + 1, os); - writeCoordinateSequence(poly.getExteriorRing().getCoordinateSequence(), true, os); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - writeCoordinateSequence(poly.getInteriorRingN(i).getCoordinateSequence(), true, - os); - } - } - - private void writeGeometryCollection(int geometryType, GeometryCollection gc, - OutStream os) throws IOException - { - writeByteOrder(os); - writeGeometryType(geometryType, gc, os); - writeInt(gc.getNumGeometries(), os); - for (int i = 0; i < gc.getNumGeometries(); i++) { - write(gc.getGeometryN(i), os); - } - } - - private void writeByteOrder(OutStream os) throws IOException - { - if (byteOrder == ByteOrderValues.LITTLE_ENDIAN) - buf[0] = WKBConstants.wkbNDR; - else - buf[0] = WKBConstants.wkbXDR; - os.write(buf, 1); - } - - private void writeGeometryType(int geometryType, Geometry g, OutStream os) - throws IOException - { - int flag3D = (outputDimension == 3) ? 0x80000000 : 0; - int typeInt = geometryType | flag3D; - typeInt |= includeSRID ? 0x20000000 : 0; - writeInt(typeInt, os); - if (includeSRID) { - writeInt(g.getSRID(), os); - } - } - - private void writeInt(int intValue, OutStream os) throws IOException - { - ByteOrderValues.putInt(intValue, buf, byteOrder); - os.write(buf, 4); - } - - private void writeCoordinateSequence(CoordinateSequence seq, boolean writeSize, OutStream os) - throws IOException - { - if (writeSize) - writeInt(seq.size(), os); - - for (int i = 0; i < seq.size(); i++) { - writeCoordinate(seq, i, os); - } - } - - private void writeCoordinate(CoordinateSequence seq, int index, OutStream os) - throws IOException - { - ByteOrderValues.putDouble(seq.getX(index), buf, byteOrder); - os.write(buf, 8); - ByteOrderValues.putDouble(seq.getY(index), buf, byteOrder); - os.write(buf, 8); - - // only write 3rd dim if caller has requested it for this writer - if (outputDimension >= 3) { - // if 3rd dim is requested, only write it if the CoordinateSequence provides it - double ordVal = Coordinate.NULL_ORDINATE; - if (seq.getDimension() >= 3) - ordVal = seq.getOrdinate(index, 2); - ByteOrderValues.putDouble(ordVal, buf, byteOrder); - os.write(buf, 8); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/WKTFileReader.java b/src/main/java/com/vividsolutions/jts/io/WKTFileReader.java deleted file mode 100644 index 759ea2a189..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKTFileReader.java +++ /dev/null @@ -1,182 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.io; - -import java.io.*; -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Reads a sequence of {@link Geometry}s in WKT format - * from a text file. - * The geometries in the file may be separated by any amount - * of whitespace and newlines. - * - * @author Martin Davis - * - */ -public class WKTFileReader -{ - private File file = null; - private Reader reader; -// private Reader fileReader = new FileReader(file); - private WKTReader wktReader; - private int count = 0; - private int limit = -1; - private int offset = 0; - - /** - * Creates a new WKTFileReader given the File to read from - * and a WKTReader to use to parse the geometries. - * - * @param file the File to read from - * @param wktReader the geometry reader to use - */ - public WKTFileReader(File file, WKTReader wktReader) - { - this.file = file; - this.wktReader = wktReader; - } - - /** - * Creates a new WKTFileReader, given the name of the file to read from. - * - * @param filename the name of the file to read from - * @param wktReader the geometry reader to use - */ - public WKTFileReader(String filename, WKTReader wktReader) - { - this(new File(filename), wktReader); - } - - /** - * Creates a new WKTFileReader, given a {@link Reader} to read from. - * - * @param reader the reader to read from - * @param wktReader the geometry reader to use - */ - public WKTFileReader(Reader reader, WKTReader wktReader) - { - this.reader = reader; - this.wktReader = wktReader; - } - - /** - * Sets the maximum number of geometries to read. - * - * @param limit the maximum number of geometries to read - */ - public void setLimit(int limit) - { - this.limit = limit; - } - - /** - * Sets the number of geometries to skip before storing. - * - * @param offset the number of geometries to skip - */ - public void setOffset(int offset) - { - this.offset = offset; - } - - /** - * Reads a sequence of geometries. - * If an offset is specified, geometries read up to the offset count are skipped. - * If a limit is specified, no more than limit geometries are read. - * - * @return the list of geometries read - * @throws IOException if an I/O exception was encountered - * @throws ParseException if an error occured reading a geometry - */ - public List read() - throws IOException, ParseException - { - // do this here so that constructors don't throw exceptions - if (file != null) - reader = new FileReader(file); - - count = 0; - try { - BufferedReader bufferedReader = new BufferedReader(reader); - try { - return read(bufferedReader); - } finally { - bufferedReader.close(); - } - } finally { - reader.close(); - } - } - - private List read(BufferedReader bufferedReader) throws IOException, - ParseException { - List geoms = new ArrayList(); - while (! isAtEndOfFile(bufferedReader) && ! isAtLimit(geoms)) { - Geometry g = wktReader.read(bufferedReader); - if (count >= offset) - geoms.add(g); - count++; - } - return geoms; - } - - private boolean isAtLimit(List geoms) - { - if (limit < 0) return false; - if (geoms.size() < limit) return false; - return true; - } - - private static final int MAX_LOOKAHEAD = 1000; - - /** - * Tests if reader is at EOF. - */ - private boolean isAtEndOfFile(BufferedReader bufferedReader) - throws IOException - { - bufferedReader.mark(MAX_LOOKAHEAD); - - StreamTokenizer tokenizer = new StreamTokenizer(bufferedReader); - int type = tokenizer.nextToken(); - - if (type == StreamTokenizer.TT_EOF) { - return true; - } - bufferedReader.reset(); - return false; - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/WKTReader.java b/src/main/java/com/vividsolutions/jts/io/WKTReader.java deleted file mode 100644 index 53865f46c9..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKTReader.java +++ /dev/null @@ -1,735 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.io.ParseException; - -import java.io.IOException; -import java.io.Reader; -import java.io.StreamTokenizer; -import java.io.StringReader; -import java.util.ArrayList; - -/** - * Converts a geometry in Well-Known Text format to a {@link Geometry}. - *

                    - * WKTReader supports - * extracting Geometry objects from either {@link Reader}s or - * {@link String}s. This allows it to function as a parser to read Geometry - * objects from text blocks embedded in other data formats (e.g. XML).

                    - *

                    - * A WKTReader is parameterized by a GeometryFactory, - * to allow it to create Geometry objects of the appropriate - * implementation. In particular, the GeometryFactory - * determines the PrecisionModel and SRID that is - * used.

                    - * - * The WKTReader converts all input numbers to the precise - * internal representation. - * - *

                    Notes:

                    - *
                      - *
                    • Keywords are case-insensitive. - *
                    • The reader supports non-standard "LINEARRING" tags. - *
                    • The reader uses Double.parseDouble to perform the conversion of ASCII - * numbers to floating point. This means it supports the Java - * syntax for floating point literals (including scientific notation). - *
                    - * - *

                    Syntax

                    - * The following syntax specification describes the version of Well-Known Text - * supported by JTS. - * (The specification uses a syntax language similar to that used in - * the C and Java language specifications.) - *

                    - * - *

                    - * WKTGeometry: one of
                    - *
                    - *       WKTPoint  WKTLineString  WKTLinearRing  WKTPolygon
                    - *       WKTMultiPoint  WKTMultiLineString  WKTMultiPolygon
                    - *       WKTGeometryCollection
                    - *
                    - * WKTPoint: POINT ( Coordinate )
                    - *
                    - * WKTLineString: LINESTRING CoordinateSequence
                    - *
                    - * WKTLinearRing: LINEARRING CoordinateSequence
                    - *
                    - * WKTPolygon: POLYGON CoordinateSequenceList
                    - *
                    - * WKTMultiPoint: MULTIPOINT CoordinateSingletonList
                    - *
                    - * WKTMultiLineString: MULTILINESTRING CoordinateSequenceList
                    - *
                    - * WKTMultiPolygon:
                    - *         MULTIPOLYGON ( CoordinateSequenceList { , CoordinateSequenceList } )
                    - *
                    - * WKTGeometryCollection: 
                    - *         GEOMETRYCOLLECTION ( WKTGeometry { , WKTGeometry } )
                    - *
                    - * CoordinateSingletonList:
                    - *         ( CoordinateSingleton { , CoordinateSingleton } )
                    - *         | EMPTY
                    - *         
                    - * CoordinateSingleton:
                    - *         ( Coordinate )
                    - *         | EMPTY
                    - *
                    - * CoordinateSequenceList:
                    - *         ( CoordinateSequence { , CoordinateSequence } )
                    - *         | EMPTY
                    - *
                    - * CoordinateSequence:
                    - *         ( Coordinate { , Coordinate } )
                    - *         | EMPTY
                    - *
                    - * Coordinate:
                    - *         Number Number Numberopt
                    - *
                    - * Number: A Java-style floating-point number (including NaN, with arbitrary case)
                    - *
                    - * 
                    - * - * - *@version 1.7 - * @see WKTWriter - */ -public class WKTReader -{ - private static final String EMPTY = "EMPTY"; - private static final String COMMA = ","; - private static final String L_PAREN = "("; - private static final String R_PAREN = ")"; - private static final String NAN_SYMBOL = "NaN"; - - private GeometryFactory geometryFactory; - private PrecisionModel precisionModel; - private StreamTokenizer tokenizer; - - /** - * Creates a reader that creates objects using the default {@link GeometryFactory}. - */ - public WKTReader() { - this(new GeometryFactory()); - } - - /** - * Creates a reader that creates objects using the given - * {@link GeometryFactory}. - * - *@param geometryFactory the factory used to create Geometrys. - */ - public WKTReader(GeometryFactory geometryFactory) { - this.geometryFactory = geometryFactory; - precisionModel = geometryFactory.getPrecisionModel(); - } - - /** - * Reads a Well-Known Text representation of a {@link Geometry} - * from a {@link String}. - * - * @param wellKnownText - * one or more strings (see the OpenGIS - * Simple Features Specification) separated by whitespace - * @return a Geometry specified by wellKnownText - * @throws ParseException - * if a parsing problem occurs - */ - public Geometry read(String wellKnownText) throws ParseException { - StringReader reader = new StringReader(wellKnownText); - try { - return read(reader); - } - finally { - reader.close(); - } - } - - /** - * Reads a Well-Known Text representation of a {@link Geometry} - * from a {@link Reader}. - * - *@param reader a Reader which will return a - * string (see the OpenGIS Simple Features Specification) - *@return a Geometry read from reader - *@throws ParseException if a parsing problem occurs - */ - public Geometry read(Reader reader) throws ParseException { - tokenizer = new StreamTokenizer(reader); - // set tokenizer to NOT parse numbers - tokenizer.resetSyntax(); - tokenizer.wordChars('a', 'z'); - tokenizer.wordChars('A', 'Z'); - tokenizer.wordChars(128 + 32, 255); - tokenizer.wordChars('0', '9'); - tokenizer.wordChars('-', '-'); - tokenizer.wordChars('+', '+'); - tokenizer.wordChars('.', '.'); - tokenizer.whitespaceChars(0, ' '); - tokenizer.commentChar('#'); - - try { - return readGeometryTaggedText(); - } - catch (IOException e) { - throw new ParseException(e.toString()); - } - } - - /** - * Returns the next array of Coordinates in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next element returned by the stream should be L_PAREN (the - * beginning of "(x1 y1, x2 y2, ..., xn yn)") or EMPTY. - *@return the next array of Coordinates in the - * stream, or an empty array if EMPTY is the next element returned by - * the stream. - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private Coordinate[] getCoordinates() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return new Coordinate[] {}; - } - ArrayList coordinates = new ArrayList(); - coordinates.add(getPreciseCoordinate()); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - coordinates.add(getPreciseCoordinate()); - nextToken = getNextCloserOrComma(); - } - Coordinate[] array = new Coordinate[coordinates.size()]; - return (Coordinate[]) coordinates.toArray(array); - } - - private Coordinate[] getCoordinatesNoLeftParen() throws IOException, ParseException { - String nextToken = null; - ArrayList coordinates = new ArrayList(); - coordinates.add(getPreciseCoordinate()); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - coordinates.add(getPreciseCoordinate()); - nextToken = getNextCloserOrComma(); - } - Coordinate[] array = new Coordinate[coordinates.size()]; - return (Coordinate[]) coordinates.toArray(array); - } - - private Coordinate getPreciseCoordinate() - throws IOException, ParseException - { - Coordinate coord = new Coordinate(); - coord.x = getNextNumber(); - coord.y = getNextNumber(); - if (isNumberNext()) { - coord.z = getNextNumber(); - } - precisionModel.makePrecise(coord); - return coord; - } - - private boolean isNumberNext() throws IOException { - int type = tokenizer.nextToken(); - tokenizer.pushBack(); - return type == StreamTokenizer.TT_WORD; - } - - /** - * Parses the next number in the stream. - * Numbers with exponents are handled. - * NaN values are handled correctly, and - * the case of the "NaN" symbol is not significant. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be a number. - *@return the next number in the stream - *@throws ParseException if the next token is not a valid number - *@throws IOException if an I/O error occurs - */ - private double getNextNumber() throws IOException, - ParseException { - int type = tokenizer.nextToken(); - switch (type) { - case StreamTokenizer.TT_WORD: - { - if (tokenizer.sval.equalsIgnoreCase(NAN_SYMBOL)) { - return Double.NaN; - } - else { - try { - return Double.parseDouble(tokenizer.sval); - } - catch (NumberFormatException ex) { - parseErrorWithLine("Invalid number: " + tokenizer.sval); - } - } - } - } - parseErrorExpected("number"); - return 0.0; - } - /** - * Returns the next EMPTY or L_PAREN in the stream as uppercase text. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be EMPTY or L_PAREN. - *@return the next EMPTY or L_PAREN in the stream as uppercase - * text. - *@throws ParseException if the next token is not EMPTY or L_PAREN - *@throws IOException if an I/O error occurs - */ - private String getNextEmptyOrOpener() throws IOException, ParseException { - String nextWord = getNextWord(); - if (nextWord.equals(EMPTY) || nextWord.equals(L_PAREN)) { - return nextWord; - } - parseErrorExpected(EMPTY + " or " + L_PAREN); - return null; - } - - /** - * Returns the next R_PAREN or COMMA in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be R_PAREN or COMMA. - *@return the next R_PAREN or COMMA in the stream - *@throws ParseException if the next token is not R_PAREN or COMMA - *@throws IOException if an I/O error occurs - */ - private String getNextCloserOrComma() throws IOException, ParseException { - String nextWord = getNextWord(); - if (nextWord.equals(COMMA) || nextWord.equals(R_PAREN)) { - return nextWord; - } - parseErrorExpected(COMMA + " or " + R_PAREN); - return null; - } - - /** - * Returns the next R_PAREN in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be R_PAREN. - *@return the next R_PAREN in the stream - *@throws ParseException if the next token is not R_PAREN - *@throws IOException if an I/O error occurs - */ - private String getNextCloser() throws IOException, ParseException { - String nextWord = getNextWord(); - if (nextWord.equals(R_PAREN)) { - return nextWord; - } - parseErrorExpected(R_PAREN); - return null; - } - - /** - * Returns the next word in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be a word. - *@return the next word in the stream as uppercase text - *@throws ParseException if the next token is not a word - *@throws IOException if an I/O error occurs - */ - private String getNextWord() throws IOException, ParseException { - int type = tokenizer.nextToken(); - switch (type) { - case StreamTokenizer.TT_WORD: - - String word = tokenizer.sval; - if (word.equalsIgnoreCase(EMPTY)) - return EMPTY; - return word; - - case '(': return L_PAREN; - case ')': return R_PAREN; - case ',': return COMMA; - } - parseErrorExpected("word"); - return null; - } - - /** - * Returns the next word in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next token must be a word. - *@return the next word in the stream as uppercase text - *@throws ParseException if the next token is not a word - *@throws IOException if an I/O error occurs - */ - private String lookaheadWord() throws IOException, ParseException { - String nextWord = getNextWord(); - tokenizer.pushBack(); - return nextWord; - } - - /** - * Throws a formatted ParseException reporting that the current token - * was unexpected. - * - * @param expected a description of what was expected - * @throws ParseException - * @throws AssertionFailedException if an invalid token is encountered - */ - private void parseErrorExpected(String expected) - throws ParseException - { - // throws Asserts for tokens that should never be seen - if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) - Assert.shouldNeverReachHere("Unexpected NUMBER token"); - if (tokenizer.ttype == StreamTokenizer.TT_EOL) - Assert.shouldNeverReachHere("Unexpected EOL token"); - - String tokenStr = tokenString(); - parseErrorWithLine("Expected " + expected + " but found " + tokenStr); - } - - private void parseErrorWithLine(String msg) - throws ParseException - { - throw new ParseException(msg + " (line " + tokenizer.lineno() + ")"); - } - - /** - * Gets a description of the current token - * - * @return a description of the current token - */ - private String tokenString() - { - switch (tokenizer.ttype) { - case StreamTokenizer.TT_NUMBER: - return ""; - case StreamTokenizer.TT_EOL: - return "End-of-Line"; - case StreamTokenizer.TT_EOF: return "End-of-Stream"; - case StreamTokenizer.TT_WORD: return "'" + tokenizer.sval + "'"; - } - return "'" + (char) tokenizer.ttype + "'"; - } - - /** - * Creates a Geometry using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <Geometry Tagged Text>. - *@return a Geometry specified by the next token - * in the stream - *@throws ParseException if the coordinates used to create a Polygon - * shell and holes do not form closed linestrings, or if an unexpected - * token was encountered - *@throws IOException if an I/O error occurs - */ - private Geometry readGeometryTaggedText() throws IOException, ParseException { - String type = null; - - try{ - type = getNextWord(); - }catch(IOException e){ - return null; - }catch(ParseException e){ - return null; - } - - if (type.equalsIgnoreCase("POINT")) { - return readPointText(); - } - else if (type.equalsIgnoreCase("LINESTRING")) { - return readLineStringText(); - } - else if (type.equalsIgnoreCase("LINEARRING")) { - return readLinearRingText(); - } - else if (type.equalsIgnoreCase("POLYGON")) { - return readPolygonText(); - } - else if (type.equalsIgnoreCase("MULTIPOINT")) { - return readMultiPointText(); - } - else if (type.equalsIgnoreCase("MULTILINESTRING")) { - return readMultiLineStringText(); - } - else if (type.equalsIgnoreCase("MULTIPOLYGON")) { - return readMultiPolygonText(); - } - else if (type.equalsIgnoreCase("GEOMETRYCOLLECTION")) { - return readGeometryCollectionText(); - } - parseErrorWithLine("Unknown geometry type: " + type); - // should never reach here - return null; - } - - /** - * Creates a Point using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <Point Text>. - *@return a Point specified by the next token in - * the stream - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private Point readPointText() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createPoint((Coordinate)null); - } - Point point = geometryFactory.createPoint(getPreciseCoordinate()); - getNextCloser(); - return point; - } - - /** - * Creates a LineString using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <LineString Text>. - *@return a LineString specified by the next - * token in the stream - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private LineString readLineStringText() throws IOException, ParseException { - return geometryFactory.createLineString(getCoordinates()); - } - - /** - * Creates a LinearRing using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <LineString Text>. - *@return a LinearRing specified by the next - * token in the stream - *@throws IOException if an I/O error occurs - *@throws ParseException if the coordinates used to create the LinearRing - * do not form a closed linestring, or if an unexpected token was - * encountered - */ - private LinearRing readLinearRingText() - throws IOException, ParseException - { - return geometryFactory.createLinearRing(getCoordinates()); - } - - /* - private MultiPoint OLDreadMultiPointText() throws IOException, ParseException { - return geometryFactory.createMultiPoint(toPoints(getCoordinates())); - } - */ - - private static final boolean ALLOW_OLD_JTS_MULTIPOINT_SYNTAX = true; - - /** - * Creates a MultiPoint using the next tokens in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <MultiPoint Text>. - *@return a MultiPoint specified by the next - * token in the stream - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private MultiPoint readMultiPointText() throws IOException, ParseException - { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createMultiPoint(new Point[0]); - } - - // check for old-style JTS syntax and parse it if present - // MD 2009-02-21 - this is only provided for backwards compatibility for a few versions - if (ALLOW_OLD_JTS_MULTIPOINT_SYNTAX) { - String nextWord = lookaheadWord(); - if (nextWord != L_PAREN) { - return geometryFactory.createMultiPoint(toPoints(getCoordinatesNoLeftParen())); - } - } - - ArrayList points = new ArrayList(); - Point point = readPointText(); - points.add(point); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - point = readPointText(); - points.add(point); - nextToken = getNextCloserOrComma(); - } - Point[] array = new Point[points.size()]; - return geometryFactory.createMultiPoint((Point[]) points.toArray(array)); - } - - /** - * Creates an array of Points having the given Coordinate - * s. - * - *@param coordinates the Coordinates with which to create the - * Points - *@return Points created using this WKTReader - * s GeometryFactory - */ - private Point[] toPoints(Coordinate[] coordinates) { - ArrayList points = new ArrayList(); - for (int i = 0; i < coordinates.length; i++) { - points.add(geometryFactory.createPoint(coordinates[i])); - } - return (Point[]) points.toArray(new Point[]{}); - } - - /** - * Creates a Polygon using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <Polygon Text>. - *@return a Polygon specified by the next token - * in the stream - *@throws ParseException if the coordinates used to create the Polygon - * shell and holes do not form closed linestrings, or if an unexpected - * token was encountered. - *@throws IOException if an I/O error occurs - */ - private Polygon readPolygonText() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createPolygon(geometryFactory.createLinearRing( - new Coordinate[]{}), new LinearRing[]{}); - } - ArrayList holes = new ArrayList(); - LinearRing shell = readLinearRingText(); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - LinearRing hole = readLinearRingText(); - holes.add(hole); - nextToken = getNextCloserOrComma(); - } - LinearRing[] array = new LinearRing[holes.size()]; - return geometryFactory.createPolygon(shell, (LinearRing[]) holes.toArray(array)); - } - - /** - * Creates a MultiLineString using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <MultiLineString Text>. - *@return a MultiLineString specified by the - * next token in the stream - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private com.vividsolutions.jts.geom.MultiLineString readMultiLineStringText() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createMultiLineString(new LineString[]{}); - } - ArrayList lineStrings = new ArrayList(); - LineString lineString = readLineStringText(); - lineStrings.add(lineString); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - lineString = readLineStringText(); - lineStrings.add(lineString); - nextToken = getNextCloserOrComma(); - } - LineString[] array = new LineString[lineStrings.size()]; - return geometryFactory.createMultiLineString((LineString[]) lineStrings.toArray(array)); - } - - /** - * Creates a MultiPolygon using the next token in the stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <MultiPolygon Text>. - *@return a MultiPolygon specified by the next - * token in the stream, or if if the coordinates used to create the - * Polygon shells and holes do not form closed linestrings. - *@throws IOException if an I/O error occurs - *@throws ParseException if an unexpected token was encountered - */ - private MultiPolygon readMultiPolygonText() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createMultiPolygon(new Polygon[]{}); - } - ArrayList polygons = new ArrayList(); - Polygon polygon = readPolygonText(); - polygons.add(polygon); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - polygon = readPolygonText(); - polygons.add(polygon); - nextToken = getNextCloserOrComma(); - } - Polygon[] array = new Polygon[polygons.size()]; - return geometryFactory.createMultiPolygon((Polygon[]) polygons.toArray(array)); - } - - /** - * Creates a GeometryCollection using the next token in the - * stream. - * - *@param tokenizer tokenizer over a stream of text in Well-known Text - * format. The next tokens must form a <GeometryCollection Text>. - *@return a GeometryCollection specified by the - * next token in the stream - *@throws ParseException if the coordinates used to create a Polygon - * shell and holes do not form closed linestrings, or if an unexpected - * token was encountered - *@throws IOException if an I/O error occurs - */ - private GeometryCollection readGeometryCollectionText() throws IOException, ParseException { - String nextToken = getNextEmptyOrOpener(); - if (nextToken.equals(EMPTY)) { - return geometryFactory.createGeometryCollection(new Geometry[]{}); - } - ArrayList geometries = new ArrayList(); - Geometry geometry = readGeometryTaggedText(); - geometries.add(geometry); - nextToken = getNextCloserOrComma(); - while (nextToken.equals(COMMA)) { - geometry = readGeometryTaggedText(); - geometries.add(geometry); - nextToken = getNextCloserOrComma(); - } - Geometry[] array = new Geometry[geometries.size()]; - return geometryFactory.createGeometryCollection((Geometry[]) geometries.toArray(array)); - } - -} - diff --git a/src/main/java/com/vividsolutions/jts/io/WKTWriter.java b/src/main/java/com/vividsolutions/jts/io/WKTWriter.java deleted file mode 100644 index 53d4224e67..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/WKTWriter.java +++ /dev/null @@ -1,777 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io; - -import com.vividsolutions.jts.geom.*; - -import com.vividsolutions.jts.util.*; -import java.io.*; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; - -/** - * Writes the Well-Known Text representation of a {@link Geometry}. - * The Well-Known Text format is defined in the - * OGC - * Simple Features Specification for SQL. - * See {@link WKTReader} for a formal specification of the format syntax. - *

                    - * The WKTWriter outputs coordinates rounded to the precision - * model. Only the maximum number of decimal places - * necessary to represent the ordinates to the required precision will be - * output. - *

                    - * The SFS WKT spec does not define a special tag for {@link LinearRing}s. - * Under the spec, rings are output as LINESTRINGs. - * In order to allow precisely specifying constructed geometries, - * JTS also supports a non-standard LINEARRING tag which is used - * to output LinearRings. - * - * @version 1.7 - * @see WKTReader - */ -public class WKTWriter -{ - /** - * Generates the WKT for a POINT - * specified by a {@link Coordinate}. - * - * @param p0 the point coordinate - * - * @return the WKT - */ - public static String toPoint(Coordinate p0) - { - return "POINT ( " + p0.x + " " + p0.y + " )"; - } - - /** - * Generates the WKT for a LINESTRING - * specified by a {@link CoordinateSequence}. - * - * @param seq the sequence to write - * - * @return the WKT string - */ - public static String toLineString(CoordinateSequence seq) - { - StringBuffer buf = new StringBuffer(); - buf.append("LINESTRING "); - if (seq.size() == 0) - buf.append(" EMPTY"); - else { - buf.append("("); - for (int i = 0; i < seq.size(); i++) { - if (i > 0) - buf.append(", "); - buf.append(seq.getX(i) + " " + seq.getY(i)); - } - buf.append(")"); - } - return buf.toString(); - } - - /** - * Generates the WKT for a LINESTRING - * specified by a {@link CoordinateSequence}. - * - * @param seq the sequence to write - * - * @return the WKT string - */ - public static String toLineString(Coordinate[] coord) - { - StringBuffer buf = new StringBuffer(); - buf.append("LINESTRING "); - if (coord.length == 0) - buf.append(" EMPTY"); - else { - buf.append("("); - for (int i = 0; i < coord.length; i++) { - if (i > 0) - buf.append(", "); - buf.append(coord[i].x + " " + coord[i].y ); - } - buf.append(")"); - } - return buf.toString(); - } - - /** - * Generates the WKT for a LINESTRING - * specified by two {@link Coordinate}s. - * - * @param p0 the first coordinate - * @param p1 the second coordinate - * - * @return the WKT - */ - public static String toLineString(Coordinate p0, Coordinate p1) - { - return "LINESTRING ( " + p0.x + " " + p0.y + ", " + p1.x + " " + p1.y + " )"; - } - - private static final int INDENT = 2; - - /** - * Creates the DecimalFormat used to write doubles - * with a sufficient number of decimal places. - * - *@param precisionModel the PrecisionModel used to determine - * the number of decimal places to write. - *@return a DecimalFormat that write double - * s without scientific notation. - */ - private static DecimalFormat createFormatter(PrecisionModel precisionModel) { - // the default number of decimal places is 16, which is sufficient - // to accomodate the maximum precision of a double. - int decimalPlaces = precisionModel.getMaximumSignificantDigits(); - // specify decimal separator explicitly to avoid problems in other locales - DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - symbols.setDecimalSeparator('.'); - String fmtString = "0" + (decimalPlaces > 0 ? "." : "") - + stringOfChar('#', decimalPlaces); - return new DecimalFormat(fmtString, symbols); - } - - /** - * Returns a String of repeated characters. - * - *@param ch the character to repeat - *@param count the number of times to repeat the character - *@return a String of characters - */ - public static String stringOfChar(char ch, int count) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < count; i++) { - buf.append(ch); - } - return buf.toString(); - } - - private int outputDimension = 2; - private DecimalFormat formatter; - private boolean isFormatted = false; - private boolean useFormatting = false; - private int level = 0; - private int coordsPerLine = -1; - private String indentTabStr = " "; - - /** - * Creates a new WKTWriter with default settings - */ - public WKTWriter() - { - } - - /** - * Creates a writer that writes {@link Geometry}s with - * the given output dimension (2 or 3). - * If the specified output dimension is 3, the Z value - * of coordinates will be written if it is present - * (i.e. if it is not Double.NaN). - * - * @param outputDimension the coordinate dimension to output (2 or 3) - */ - public WKTWriter(int outputDimension) { - this.outputDimension = outputDimension; - - if (outputDimension < 2 || outputDimension > 3) - throw new IllegalArgumentException("Invalid output dimension (must be 2 or 3)"); - } - - /** - * Sets whether the output will be formatted. - * - * @param isFormatted true if the output is to be formatted - */ - public void setFormatted(boolean isFormatted) - { - this.isFormatted = isFormatted; - } - - /** - * Sets the maximum number of coordinates per line - * written in formatted output. - * If the provided coordinate number is <= 0, - * coordinates will be written all on one line. - * - * @param coordsPerLine the number of coordinates per line to output. - */ - public void setMaxCoordinatesPerLine(int coordsPerLine) - { - this.coordsPerLine = coordsPerLine; - } - - /** - * Sets the tab size to use for indenting. - * - * @param size the number of spaces to use as the tab string - * @throws IllegalArgumentException if the size is non-positive - */ - public void setTab(int size) - { - if(size <= 0) - throw new IllegalArgumentException("Tab count must be positive"); - this.indentTabStr = stringOfChar(' ', size); - } - - /** - * Converts a Geometry to its Well-known Text representation. - * - *@param geometry a Geometry to process - *@return a string (see the OpenGIS Simple - * Features Specification) - */ - public String write(Geometry geometry) - { - Writer sw = new StringWriter(); - try { - writeFormatted(geometry, isFormatted, sw); - } - catch (IOException ex) { - Assert.shouldNeverReachHere(); - } - return sw.toString(); - } - - /** - * Converts a Geometry to its Well-known Text representation. - * - *@param geometry a Geometry to process - */ - public void write(Geometry geometry, Writer writer) - throws IOException - { - writeFormatted(geometry, false, writer); - } - - /** - * Same as write, but with newlines and spaces to make the - * well-known text more readable. - * - *@param geometry a Geometry to process - *@return a string (see the OpenGIS Simple - * Features Specification), with newlines and spaces - */ - public String writeFormatted(Geometry geometry) - { - Writer sw = new StringWriter(); - try { - writeFormatted(geometry, true, sw); - } - catch (IOException ex) { - Assert.shouldNeverReachHere(); - } - return sw.toString(); - } - /** - * Same as write, but with newlines and spaces to make the - * well-known text more readable. - * - *@param geometry a Geometry to process - */ - public void writeFormatted(Geometry geometry, Writer writer) - throws IOException - { - writeFormatted(geometry, true, writer); - } - /** - * Converts a Geometry to its Well-known Text representation. - * - *@param geometry a Geometry to process - */ - private void writeFormatted(Geometry geometry, boolean useFormatting, Writer writer) - throws IOException - { - this.useFormatting = useFormatting; - formatter = createFormatter(geometry.getPrecisionModel()); - appendGeometryTaggedText(geometry, 0, writer); - } - - - /** - * Converts a Geometry to <Geometry Tagged Text> format, - * then appends it to the writer. - * - *@param geometry the Geometry to process - *@param writer the output writer to append to - */ - private void appendGeometryTaggedText(Geometry geometry, int level, Writer writer) - throws IOException - { - indent(level, writer); - - if (geometry instanceof Point) { - Point point = (Point) geometry; - appendPointTaggedText(point.getCoordinate(), level, writer, point.getPrecisionModel()); - } - else if (geometry instanceof LinearRing) { - appendLinearRingTaggedText((LinearRing) geometry, level, writer); - } - else if (geometry instanceof LineString) { - appendLineStringTaggedText((LineString) geometry, level, writer); - } - else if (geometry instanceof Polygon) { - appendPolygonTaggedText((Polygon) geometry, level, writer); - } - else if (geometry instanceof MultiPoint) { - appendMultiPointTaggedText((MultiPoint) geometry, level, writer); - } - else if (geometry instanceof MultiLineString) { - appendMultiLineStringTaggedText((MultiLineString) geometry, level, writer); - } - else if (geometry instanceof MultiPolygon) { - appendMultiPolygonTaggedText((MultiPolygon) geometry, level, writer); - } - else if (geometry instanceof GeometryCollection) { - appendGeometryCollectionTaggedText((GeometryCollection) geometry, level, writer); - } - else { - Assert.shouldNeverReachHere("Unsupported Geometry implementation:" - + geometry.getClass()); - } - } - - /** - * Converts a Coordinate to <Point Tagged Text> format, - * then appends it to the writer. - * - *@param coordinate the Coordinate to process - *@param writer the output writer to append to - *@param precisionModel the PrecisionModel to use to convert - * from a precise coordinate to an external coordinate - */ - private void appendPointTaggedText(Coordinate coordinate, int level, Writer writer, - PrecisionModel precisionModel) - throws IOException - { - writer.write("POINT "); - appendPointText(coordinate, level, writer, precisionModel); - } - - /** - * Converts a LineString to <LineString Tagged Text> - * format, then appends it to the writer. - * - *@param lineString the LineString to process - *@param writer the output writer to append to - */ - private void appendLineStringTaggedText(LineString lineString, int level, Writer writer) - throws IOException - { - writer.write("LINESTRING "); - appendLineStringText(lineString, level, false, writer); - } - - /** - * Converts a LinearRing to <LinearRing Tagged Text> - * format, then appends it to the writer. - * - *@param linearRing the LinearRing to process - *@param writer the output writer to append to - */ - private void appendLinearRingTaggedText(LinearRing linearRing, int level, Writer writer) - throws IOException - { - writer.write("LINEARRING "); - appendLineStringText(linearRing, level, false, writer); - } - - /** - * Converts a Polygon to <Polygon Tagged Text> format, - * then appends it to the writer. - * - *@param polygon the Polygon to process - *@param writer the output writer to append to - */ - private void appendPolygonTaggedText(Polygon polygon, int level, Writer writer) - throws IOException - { - writer.write("POLYGON "); - appendPolygonText(polygon, level, false, writer); - } - - /** - * Converts a MultiPoint to <MultiPoint Tagged Text> - * format, then appends it to the writer. - * - *@param multipoint the MultiPoint to process - *@param writer the output writer to append to - */ - private void appendMultiPointTaggedText(MultiPoint multipoint, int level, Writer writer) - throws IOException - { - writer.write("MULTIPOINT "); - appendMultiPointText(multipoint, level, writer); - } - - /** - * Converts a MultiLineString to <MultiLineString Tagged - * Text> format, then appends it to the writer. - * - *@param multiLineString the MultiLineString to process - *@param writer the output writer to append to - */ - private void appendMultiLineStringTaggedText(MultiLineString multiLineString, int level, - Writer writer) - throws IOException - { - writer.write("MULTILINESTRING "); - appendMultiLineStringText(multiLineString, level, false, writer); - } - - /** - * Converts a MultiPolygon to <MultiPolygon Tagged Text> - * format, then appends it to the writer. - * - *@param multiPolygon the MultiPolygon to process - *@param writer the output writer to append to - */ - private void appendMultiPolygonTaggedText(MultiPolygon multiPolygon, int level, Writer writer) - throws IOException - { - writer.write("MULTIPOLYGON "); - appendMultiPolygonText(multiPolygon, level, writer); - } - - /** - * Converts a GeometryCollection to <GeometryCollection - * Tagged Text> format, then appends it to the writer. - * - *@param geometryCollection the GeometryCollection to process - *@param writer the output writer to append to - */ - private void appendGeometryCollectionTaggedText(GeometryCollection geometryCollection, int level, - Writer writer) - throws IOException - { - writer.write("GEOMETRYCOLLECTION "); - appendGeometryCollectionText(geometryCollection, level, writer); - } - - /** - * Converts a Coordinate to <Point Text> format, then - * appends it to the writer. - * - *@param coordinate the Coordinate to process - *@param writer the output writer to append to - *@param precisionModel the PrecisionModel to use to convert - * from a precise coordinate to an external coordinate - */ - private void appendPointText(Coordinate coordinate, int level, Writer writer, - PrecisionModel precisionModel) - throws IOException - { - if (coordinate == null) { - writer.write("EMPTY"); - } - else { - writer.write("("); - appendCoordinate(coordinate, writer); - writer.write(")"); - } - } - - /** - * Appends the i'th coordinate from the sequence to the writer - * - * @param seq the CoordinateSequence to process - * @param i the index of the coordinate to write - * @param writer the output writer to append to - */ - private void appendCoordinate(CoordinateSequence seq, int i, Writer writer) - throws IOException - { - writer.write(writeNumber(seq.getX(i)) + " " + writeNumber(seq.getY(i))); - if (outputDimension >= 3 && seq.getDimension() >= 3) { - double z = seq.getOrdinate(i, 3); - if (! Double.isNaN(z)) { - writer.write(" "); - writer.write(writeNumber(z)); - } - } - } - - /** - * Converts a Coordinate to <Point> format, - * then appends it to the writer. - * - *@param coordinate the Coordinate to process - *@param writer the output writer to append to - */ - private void appendCoordinate(Coordinate coordinate, Writer writer) - throws IOException - { - writer.write(writeNumber(coordinate.x) + " " + writeNumber(coordinate.y)); - if (outputDimension >= 3 && ! Double.isNaN(coordinate.z)) { - writer.write(" "); - writer.write(writeNumber(coordinate.z)); - } - } - - /** - * Converts a double to a String, not in scientific - * notation. - * - *@param d the double to convert - *@return the double as a String, not in - * scientific notation - */ - private String writeNumber(double d) { - return formatter.format(d); - } - - /** - * Converts a LineString to <LineString Text> format, then - * appends it to the writer. - * - *@param lineString the LineString to process - *@param writer the output writer to append to - */ - private void appendSequenceText(CoordinateSequence seq, int level, boolean doIndent, Writer writer) - throws IOException - { - if (seq.size() == 0) { - writer.write("EMPTY"); - } - else { - if (doIndent) indent(level, writer); - writer.write("("); - for (int i = 0; i < seq.size(); i++) { - if (i > 0) { - writer.write(", "); - if (coordsPerLine > 0 - && i % coordsPerLine == 0) { - indent(level + 1, writer); - } - } - appendCoordinate(seq, i, writer); - } - writer.write(")"); - } - } - - /** - * Converts a LineString to <LineString Text> format, then - * appends it to the writer. - * - *@param lineString the LineString to process - *@param writer the output writer to append to - */ - private void appendLineStringText(LineString lineString, int level, boolean doIndent, Writer writer) - throws IOException - { - if (lineString.isEmpty()) { - writer.write("EMPTY"); - } - else { - if (doIndent) indent(level, writer); - writer.write("("); - for (int i = 0; i < lineString.getNumPoints(); i++) { - if (i > 0) { - writer.write(", "); - if (coordsPerLine > 0 - && i % coordsPerLine == 0) { - indent(level + 1, writer); - } - } - appendCoordinate(lineString.getCoordinateN(i), writer); - } - writer.write(")"); - } - } - - /** - * Converts a Polygon to <Polygon Text> format, then - * appends it to the writer. - * - *@param polygon the Polygon to process - *@param writer the output writer to append to - */ - private void appendPolygonText(Polygon polygon, int level, boolean indentFirst, Writer writer) - throws IOException - { - if (polygon.isEmpty()) { - writer.write("EMPTY"); - } - else { - if (indentFirst) indent(level, writer); - writer.write("("); - appendLineStringText(polygon.getExteriorRing(), level, false, writer); - for (int i = 0; i < polygon.getNumInteriorRing(); i++) { - writer.write(", "); - appendLineStringText(polygon.getInteriorRingN(i), level + 1, true, writer); - } - writer.write(")"); - } - } - - /** - * Converts a MultiPoint to <MultiPoint Text> format, then - * appends it to the writer. - * - *@param multiPoint the MultiPoint to process - *@param writer the output writer to append to - */ - private void appendMultiPointText(MultiPoint multiPoint, int level, Writer writer) - throws IOException - { - if (multiPoint.isEmpty()) { - writer.write("EMPTY"); - } - else { - writer.write("("); - for (int i = 0; i < multiPoint.getNumGeometries(); i++) { - if (i > 0) { - writer.write(", "); - indentCoords(i, level + 1, writer); - } - writer.write("("); - appendCoordinate(((Point) multiPoint.getGeometryN(i)).getCoordinate(), writer); - writer.write(")"); - } - writer.write(")"); - } - } - - /** - * Converts a MultiLineString to <MultiLineString Text> - * format, then appends it to the writer. - * - *@param multiLineString the MultiLineString to process - *@param writer the output writer to append to - */ - private void appendMultiLineStringText(MultiLineString multiLineString, int level, boolean indentFirst, - Writer writer) - throws IOException - { - if (multiLineString.isEmpty()) { - writer.write("EMPTY"); - } - else { - int level2 = level; - boolean doIndent = indentFirst; - writer.write("("); - for (int i = 0; i < multiLineString.getNumGeometries(); i++) { - if (i > 0) { - writer.write(", "); - level2 = level + 1; - doIndent = true; - } - appendLineStringText((LineString) multiLineString.getGeometryN(i), level2, doIndent, writer); - } - writer.write(")"); - } - } - - /** - * Converts a MultiPolygon to <MultiPolygon Text> format, - * then appends it to the writer. - * - *@param multiPolygon the MultiPolygon to process - *@param writer the output writer to append to - */ - private void appendMultiPolygonText(MultiPolygon multiPolygon, int level, Writer writer) - throws IOException - { - if (multiPolygon.isEmpty()) { - writer.write("EMPTY"); - } - else { - int level2 = level; - boolean doIndent = false; - writer.write("("); - for (int i = 0; i < multiPolygon.getNumGeometries(); i++) { - if (i > 0) { - writer.write(", "); - level2 = level + 1; - doIndent = true; - } - appendPolygonText((Polygon) multiPolygon.getGeometryN(i), level2, doIndent, writer); - } - writer.write(")"); - } - } - - /** - * Converts a GeometryCollection to <GeometryCollectionText> - * format, then appends it to the writer. - * - *@param geometryCollection the GeometryCollection to process - *@param writer the output writer to append to - */ - private void appendGeometryCollectionText(GeometryCollection geometryCollection, int level, - Writer writer) - throws IOException - { - if (geometryCollection.isEmpty()) { - writer.write("EMPTY"); - } - else { - int level2 = level; - writer.write("("); - for (int i = 0; i < geometryCollection.getNumGeometries(); i++) { - if (i > 0) { - writer.write(", "); - level2 = level + 1; - } - appendGeometryTaggedText(geometryCollection.getGeometryN(i), level2, writer); - } - writer.write(")"); - } - } - - private void indentCoords(int coordIndex, int level, Writer writer) - throws IOException - { - if (coordsPerLine <= 0 - || coordIndex % coordsPerLine != 0) - return; - indent(level, writer); - } - - private void indent(int level, Writer writer) - throws IOException - { - if (! useFormatting || level <= 0) - return; - writer.write("\n"); - for (int i = 0; i < level; i++) { - writer.write(indentTabStr); - } - } - - -} - diff --git a/src/main/java/com/vividsolutions/jts/io/gml2/GMLConstants.java b/src/main/java/com/vividsolutions/jts/io/gml2/GMLConstants.java deleted file mode 100644 index 02de82f818..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/gml2/GMLConstants.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io.gml2; - -/** - * Various constant strings associated with GML format. - */ -final public class GMLConstants{ - - // Namespace constants - public static final String GML_NAMESPACE = "http://www.opengis.net/gml"; - public static final String GML_PREFIX = "gml"; - - // Source Coordinate System - public static final String GML_ATTR_SRSNAME = "srsName"; - - // GML associative types - public static final String GML_GEOMETRY_MEMBER = "geometryMember"; - public static final String GML_POINT_MEMBER = "pointMember"; - public static final String GML_POLYGON_MEMBER = "polygonMember"; - public static final String GML_LINESTRING_MEMBER = "lineStringMember"; - public static final String GML_OUTER_BOUNDARY_IS = "outerBoundaryIs"; - public static final String GML_INNER_BOUNDARY_IS = "innerBoundaryIs"; - - // Primitive Geometries - public static final String GML_POINT = "Point"; - public static final String GML_LINESTRING = "LineString"; - public static final String GML_LINEARRING = "LinearRing"; - public static final String GML_POLYGON = "Polygon"; - public static final String GML_BOX = "Box"; - - // Aggregate Geometries - public static final String GML_MULTI_GEOMETRY = "MultiGeometry"; - public static final String GML_MULTI_POINT = "MultiPoint"; - public static final String GML_MULTI_LINESTRING = "MultiLineString"; - public static final String GML_MULTI_POLYGON = "MultiPolygon"; - - // Coordinates - public static final String GML_COORDINATES = "coordinates"; - public static final String GML_COORD = "coord"; - public static final String GML_COORD_X = "X"; - public static final String GML_COORD_Y = "Y"; - public static final String GML_COORD_Z = "Z"; -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/io/gml2/GMLHandler.java b/src/main/java/com/vividsolutions/jts/io/gml2/GMLHandler.java deleted file mode 100644 index 431585d4cb..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/gml2/GMLHandler.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io.gml2; - -import java.util.*; - -import org.xml.sax.*; -import org.xml.sax.helpers.AttributesImpl; -import org.xml.sax.helpers.DefaultHandler; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.io.gml2.GeometryStrategies.ParseStrategy; - -/** - * A SAX {@link DefaultHandler} which builds {@link Geometry}s - * from GML2-formatted geometries. - * An XML parser can delegate SAX events to this handler - * to parse and building Geometrys. - *

                    - * This handler currently ignores both namespaces and prefixes. - * - * Hints: - *

                      - *
                    • If your parent handler is a DefaultHandler register the parent handler to receive the errors and locator calls. - *
                    • Use {@link GeometryStrategies#findStrategy(String, String)} to help check for applicability - *
                    - * - * @see DefaultHandler - * - * @author David Zwiers, Vivid Solutions. - */ -public class GMLHandler extends DefaultHandler { - - /** - * This class is intended to log the SAX acitivity within a given element until its termination. - * At this time, a new object of value is created and passed to the parent. - * An object of value is typically either java.lang.* or a JTS Geometry - * This class is not intended for use outside this distribution, - * and may change in subsequent versions. - * - * @author David Zwiers, Vivid Solutions. - */ - static class Handler { - protected Attributes attrs = null; - - protected ParseStrategy strategy; - - /** - * @param strategy - * @param attributes Nullable - */ - public Handler(ParseStrategy strategy, Attributes attributes) { - if (attributes != null) - this.attrs = new AttributesImpl(attributes); - this.strategy = strategy; - } - - protected StringBuffer text = null; - - /** - * Caches text for the future - * @param str - */ - public void addText(String str) { - if (text == null) - text = new StringBuffer(); - text.append(str); - } - - protected List children = null; - - /** - * Store param for the future - * - * @param obj - */ - public void keep(Object obj) { - if (children == null) - children = new LinkedList(); - children.add(obj); - - } - - /** - * @param gf GeometryFactory - * @return Parsed Object - * @throws SAXException - */ - public Object create(GeometryFactory gf) throws SAXException { - return strategy.parse(this, gf); - } - } - - private Stack stack = new Stack(); - - private ErrorHandler delegate = null; - - private GeometryFactory gf = null; - - /** - * Creates a new handler. - * Allows the user to specify a delegate object for error / warning messages. - * If the delegate also implements ContentHandler then the document Locator will be passed on. - * - * @param gf Geometry Factory - * @param delegate Nullable - * - * @see ErrorHandler - * @see ContentHandler - * @see ContentHandler#setDocumentLocator(org.xml.sax.Locator) - * @see org.xml.sax.Locator - * - */ - public GMLHandler(GeometryFactory gf, ErrorHandler delegate) { - this.delegate = delegate; - this.gf = gf; - stack.push(new Handler(null, null)); - } - - /** - * Tests whether this handler has completed parsing - * a geometry. - * If this is the case, {@link #getGeometry()} can be called - * to get the value of the parsed geometry. - * - * @return if the parsing of the geometry is complete - */ - public boolean isGeometryComplete() - { - if (stack.size() > 1) - return false; - // top level node on stack needs to have at least one child - Handler h = (Handler) stack.peek(); - if (h.children.size() < 1) - return false; - return true; - - } - - /** - * Gets the geometry parsed by this handler. - * This method should only be called AFTER the parser has completed execution - * - * @return the parsed Geometry, or a GeometryCollection if more than one geometry was parsed - * @throws IllegalStateException if called before the parse is complete - */ - public Geometry getGeometry() { - if (stack.size() == 1) { - Handler h = (Handler) stack.peek(); - if (h.children.size() == 1) - return (Geometry) h.children.get(0); - return gf.createGeometryCollection( - (Geometry[]) h.children.toArray(new Geometry[stack.size()])); - } - throw new IllegalStateException( - "Parse did not complete as expected, there are " + stack.size() - + " elements on the Stack"); - } - - ////////////////////////////////////////////// - // Parsing Methods - - /** - * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) - */ - public void characters(char[] ch, int start, int length) throws SAXException { - if (!stack.isEmpty()) - ((Handler) stack.peek()).addText(new String(ch, start, length)); - } - - /** - * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int) - */ - public void ignorableWhitespace(char[] ch, int start, int length) - throws SAXException { - if (!stack.isEmpty()) - ((Handler) stack.peek()).addText(" "); - } - - /** - * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) - */ - public void endElement(String uri, String localName, String qName) - throws SAXException { - Handler thisAction = (Handler) stack.pop(); - ((Handler) stack.peek()).keep(thisAction.create(gf)); - } - - /** - * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) - */ - public void startElement(String uri, String localName, String qName, - Attributes attributes) throws SAXException { - // create a handler - ParseStrategy ps = GeometryStrategies.findStrategy(uri, localName); - if (ps == null) { - String qn = qName.substring(qName.indexOf(':') + 1, qName.length()); - ps = GeometryStrategies.findStrategy(null, qn); - } - Handler h = new Handler(ps, attributes); - // and add it to the stack - stack.push(h); - } - - ////////////////////////////////////////////// - // Logging Methods - - /** - * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator) - */ - public void setDocumentLocator(Locator locator) { - this.locator = locator; - if (delegate != null && delegate instanceof ContentHandler) - ((ContentHandler) delegate).setDocumentLocator(locator); - - } - - private Locator locator = null; - - protected Locator getDocumentLocator() { - return locator; - } - - ////////////////////////////////////////////// - // ERROR Methods - - /** - * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException) - */ - public void fatalError(SAXParseException e) throws SAXException { - if (delegate != null) - delegate.fatalError(e); - else - super.fatalError(e); - } - - /** - * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException) - */ - public void error(SAXParseException e) throws SAXException { - if (delegate != null) - delegate.error(e); - else - super.error(e); - } - - /** - * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException) - */ - public void warning(SAXParseException e) throws SAXException { - if (delegate != null) - delegate.warning(e); - else - super.warning(e); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/io/gml2/GMLReader.java b/src/main/java/com/vividsolutions/jts/io/gml2/GMLReader.java deleted file mode 100644 index 0c4c66c19f..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/gml2/GMLReader.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io.gml2; - -import java.io.*; - -import javax.xml.parsers.*; - -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import com.vividsolutions.jts.geom.*; - -/** - * Reads a GML2 geometry from an XML fragment into a {@link Geometry}. - *

                    - * An example of the GML2 format handled is: - *

                    - *   
                    - *  	24824.045318333192,38536.15071012041
                    - *  		26157.378651666528,37567.42733944659 26666.666,36000.0
                    - *  		26157.378651666528,34432.57266055341
                    - *  		24824.045318333192,33463.84928987959
                    - *  		23175.954681666804,33463.84928987959
                    - *  		21842.621348333472,34432.57266055341 21333.333,36000.0
                    - *  		21842.621348333472,37567.42733944659
                    - *  		23175.954681666808,38536.15071012041 
                    - *  
                    - * 
                    - * - * The reader ignores namespace prefixes, - * and disables both the validation and namespace options on the SAXParser. - * This class requires the presence of a SAX Parser available via the - * {@link javax.xml.parsers.SAXParserFactory#newInstance()} - * method. - *

                    - * A specification of the GML XML format - * can be found at the OGC web site: http://www.opengeospatial.org/. - *

                    - * It is the caller's responsibility to ensure that the supplied {@link PrecisionModel} - * matches the precision of the incoming data. - * If a lower precision for the data is required, a subsequent - * process must be run on the data to reduce its precision. - *

                    - * To parse and build geometry directly from a SAX stream, see {@link GMLHandler}. - * - * @author David Zwiers, Vivid Solutions. - * - * @see GMLHandler - */ -public class GMLReader -{ - - /** - * Reads a GML2 Geometry from a String into a single {@link Geometry} - * - * If a collection of geometries is found, a {@link GeometryCollection} is returned. - * - * @param gml The GML String to parse - * @param geometryFactory When null, a default will be used. - * @return the resulting JTS Geometry - * - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException - * - * @see #read(Reader, GeometryFactory) - */ - public Geometry read(String gml, GeometryFactory geometryFactory) throws SAXException, IOException, ParserConfigurationException{ - return read(new StringReader(gml),geometryFactory); - } - - /** - * Reads a GML2 Geometry from a {@link Reader} into a single {@link Geometry} - * - * If a collection of Geometries is found, a {@link GeometryCollection} is returned. - * - * @param reader The input source - * @param geometryFactory When null, a default will be used. - * @return The resulting JTS Geometry - * @throws SAXException - * @throws IOException - */ - public Geometry read(Reader reader, GeometryFactory geometryFactory) throws SAXException, IOException, ParserConfigurationException{ - SAXParserFactory fact = SAXParserFactory.newInstance(); - - fact.setNamespaceAware(false); - fact.setValidating(false); - - SAXParser parser = fact.newSAXParser(); - - if(geometryFactory == null) - geometryFactory = new GeometryFactory(); - - GMLHandler gh = new GMLHandler(geometryFactory,null); - parser.parse(new InputSource(reader), (DefaultHandler)gh); - - return gh.getGeometry(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/io/gml2/GMLWriter.java b/src/main/java/com/vividsolutions/jts/io/gml2/GMLWriter.java deleted file mode 100644 index dad7391d4a..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/gml2/GMLWriter.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io.gml2; - -import java.io.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Writes {@link Geometry}s as XML fragments in GML2 format. - * Allows specifying the XML prefix, namespace and srsName - * of the emitted GML. - * Also allows adding custom root elements - * to support GML extensions such as KML. - * With appropriate settings for prefix (none) and custom root elements - * this class can be used to write out geometry in KML format. - *

                    - * An example of the output that can be generated is: - * - *

                    - * 
                    - *   
                    - *     6.03,8.17 7.697,6.959 8.333,5.0 7.697,3.041 6.03,1.83 3.97,1.83 2.303,3.041 1.667,5.0 2.303,6.959 3.97,8.17 
                    - *   
                    - * 
                    - * 
                    - * - *

                    - * This class does not rely on any external XML libraries. - * - * @author David Zwiers, Vivid Solutions - * @author Martin Davis - */ -public class GMLWriter { - private final String INDENT = " "; - - private int startingIndentIndex = 0; - - private int maxCoordinatesPerLine = 10; - - private boolean emitNamespace = false; - - private boolean isRootTag = false; - - private String prefix = GMLConstants.GML_PREFIX; - private String namespace = GMLConstants.GML_NAMESPACE; - private String srsName = null; - - private String[] customElements = null; - - /** - * Creates a writer which outputs GML with default settings. - * The defaults are: - *

                      - *
                    • the namespace prefix is gml: - *
                    • no namespace prefix declaration is written - *
                    • no srsName attribute is written - *
                    - */ - public GMLWriter() { - } - - /** - * Creates a writer which may emit the GML namespace prefix - * declaration in the geometry root element. - * - * @param emitNamespace trueif the GML namespace prefix declaration should be written - * in the geometry root element - */ - public GMLWriter(boolean emitNamespace) { - this.setNamespace(emitNamespace); - } - - /** - * Specifies the namespace prefix to write on each GML tag. - * A null or blank prefix may be used to indicate no prefix. - *

                    - * The default is to write gml: as the namespace prefix. - * - * @param prefix the namespace prefix to use (null or blank if none) - */ - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - /** - * Sets the value of the srsName attribute - * to be written into the root geometry tag. - * If the value is null or blank no srsName attribute will be written. - * The provided value must be a valid XML attribute value - * - it will not be XML-escaped. - *

                    - * The default is not to write the srsName attribute. - * - * @param srsName the srsName attribute value - */ - public void setSrsName(String srsName) { - this.srsName = srsName; - } - - /** - * Determines whether a GML namespace declaration will be written in the - * opening tag of geometries. Useful in XML-aware environments which - * parse the geometries before use, such as XSLT. - * - * @param emitNamespace true if the GML namespace prefix declaration - * should be written in the root geometry element - */ - public void setNamespace(boolean emitNamespace) { - this.emitNamespace = emitNamespace; - } - - /** - * Specifies a list of custom elements - * which are written after the opening tag - * of the root element. - * The text contained in the string sequence should form valid XML markup. - * The specified strings are written one per line immediately after - * the root geometry tag line. - *

                    - * For instance, this is useful for adding KML-specific geometry parameters - * such as <extrude> - * - * @param customElements a list of the custom element strings, or null if none - */ - public void setCustomElements(String[] customElements) { - this.customElements = customElements; - } - - /** - * Sets the starting column index for pretty printing - * - * @param indent - */ - public void setStartingIndentIndex(int indent) { - if (indent < 0) - indent = 0; - startingIndentIndex = indent; - } - - /** - * Sets the number of coordinates printed per line. - * - * @param num - */ - public void setMaxCoordinatesPerLine(int num) { - if (num < 1) - throw new IndexOutOfBoundsException( - "Invalid coordinate count per line, must be > 0"); - maxCoordinatesPerLine = num; - } - - /** - * Writes a {@link Geometry} in GML2 format to a String. - * - * @param geom - * @return String GML2 Encoded Geometry - */ - public String write(Geometry geom) - { - StringWriter writer = new StringWriter(); - try { - write(geom, writer); - } - catch (IOException ex) { - Assert.shouldNeverReachHere(); - } - return writer.toString(); - } - - /** - * Writes a {@link Geometry} in GML2 format into a {@link Writer}. - * - * @param geom Geometry to encode - * @param writer Stream to encode to. - * @throws IOException - */ - public void write(Geometry geom, Writer writer) throws IOException { - write(geom, writer, startingIndentIndex); - } - - private void write(Geometry geom, Writer writer, int level) - throws IOException - { - isRootTag = true; - if (geom instanceof Point) { - writePoint((Point) geom, writer, level); - } else if (geom instanceof LineString) { - writeLineString((LineString) geom, writer, level); - } else if (geom instanceof Polygon) { - writePolygon((Polygon) geom, writer, level); - } else if (geom instanceof MultiPoint) { - writeMultiPoint((MultiPoint) geom, writer, level); - } else if (geom instanceof MultiLineString) { - writeMultiLineString((MultiLineString) geom, writer, level); - } else if (geom instanceof MultiPolygon) { - writeMultiPolygon((MultiPolygon) geom, writer, level); - } else if (geom instanceof GeometryCollection) { - writeGeometryCollection((GeometryCollection) geom, writer, - startingIndentIndex); - } else { - throw new IllegalArgumentException("Unhandled geometry type: " - + geom.getGeometryType()); - } - writer.flush(); - } - - // 1195156.78946687,382069.533723461 - private void writePoint(Point p, Writer writer, int level) throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_POINT, p, writer); - - write(new Coordinate[] { p.getCoordinate() }, writer, level + 1); - - startLine(level, writer); - endGeomTag(GMLConstants.GML_POINT, writer); - } - - //1195123.37289257,381985.763974674 1195120.22369473,381964.660533343 1195118.14929823,381942.597718511 - private void writeLineString(LineString ls, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_LINESTRING, ls, writer); - - write(ls.getCoordinates(), writer, level + 1); - - startLine(level, writer); - endGeomTag(GMLConstants.GML_LINESTRING, writer); - } - - //1226890.26761027,1466433.47430292 1226880.59239079,1466427.03208053...> - private void writeLinearRing(LinearRing lr, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_LINEARRING, lr, writer); - - write(lr.getCoordinates(), writer, level + 1); - - startLine(level, writer); - endGeomTag(GMLConstants.GML_LINEARRING, writer); - } - - private void writePolygon(Polygon p, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_POLYGON, p, writer); - - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_OUTER_BOUNDARY_IS, null, writer); - - writeLinearRing((LinearRing) p.getExteriorRing(), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_OUTER_BOUNDARY_IS, writer); - - for (int t = 0; t < p.getNumInteriorRing(); t++) { - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_INNER_BOUNDARY_IS, null, writer); - - writeLinearRing((LinearRing) p.getInteriorRingN(t), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_INNER_BOUNDARY_IS, writer); - } - - startLine(level, writer); - endGeomTag(GMLConstants.GML_POLYGON, writer); - } - - private void writeMultiPoint(MultiPoint mp, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_MULTI_POINT, mp, writer); - - for (int t = 0; t < mp.getNumGeometries(); t++) { - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_POINT_MEMBER, null, writer); - - writePoint((Point) mp.getGeometryN(t), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_POINT_MEMBER, writer); - } - startLine(level, writer); - endGeomTag(GMLConstants.GML_MULTI_POINT, writer); - } - - private void writeMultiLineString(MultiLineString mls, Writer writer, - int level) throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_MULTI_LINESTRING, mls, writer); - - for (int t = 0; t < mls.getNumGeometries(); t++) { - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_LINESTRING_MEMBER, null, writer); - - writeLineString((LineString) mls.getGeometryN(t), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_LINESTRING_MEMBER, writer); - } - startLine(level, writer); - endGeomTag(GMLConstants.GML_MULTI_LINESTRING, writer); - } - - private void writeMultiPolygon(MultiPolygon mp, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_MULTI_POLYGON, mp, writer); - - for (int t = 0; t < mp.getNumGeometries(); t++) { - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_POLYGON_MEMBER, null, writer); - - writePolygon((Polygon) mp.getGeometryN(t), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_POLYGON_MEMBER, writer); - } - startLine(level, writer); - endGeomTag(GMLConstants.GML_MULTI_POLYGON, writer); - } - - private void writeGeometryCollection(GeometryCollection gc, Writer writer, - int level) throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_MULTI_GEOMETRY, gc, writer); - - for (int t = 0; t < gc.getNumGeometries(); t++) { - startLine(level + 1, writer); - startGeomTag(GMLConstants.GML_GEOMETRY_MEMBER, null, writer); - - write(gc.getGeometryN(t), writer, level + 2); - - startLine(level + 1, writer); - endGeomTag(GMLConstants.GML_GEOMETRY_MEMBER, writer); - } - startLine(level, writer); - endGeomTag(GMLConstants.GML_MULTI_GEOMETRY, writer); - } - - private static final String coordinateSeparator = ","; - - private static final String tupleSeparator = " "; - - /** - * Takes a list of coordinates and converts it to GML.
                    - * 2d and 3d aware. - * - * @param coords array of coordinates - * @throws IOException - */ - private void write(Coordinate[] coords, Writer writer, int level) - throws IOException { - startLine(level, writer); - startGeomTag(GMLConstants.GML_COORDINATES, null, writer); - - int dim = 2; - - if (coords.length > 0) { - if (!(Double.isNaN(coords[0].z))) - dim = 3; - } - - boolean isNewLine = true; - for (int i = 0; i < coords.length; i++) { - if (isNewLine) { - startLine(level + 1, writer); - isNewLine = false; - } - if (dim == 2) { - writer.write("" + coords[i].x); - writer.write(coordinateSeparator); - writer.write("" + coords[i].y); - } else if (dim == 3) { - writer.write("" + coords[i].x); - writer.write(coordinateSeparator); - writer.write("" + coords[i].y); - writer.write(coordinateSeparator); - writer.write("" + coords[i].z); - } - writer.write(tupleSeparator); - - // break output lines to prevent them from getting too long - if ((i + 1) % maxCoordinatesPerLine == 0 && i < coords.length - 1) { - writer.write("\n"); - isNewLine = true; - } - } - if (!isNewLine) - writer.write("\n"); - - startLine(level, writer); - endGeomTag(GMLConstants.GML_COORDINATES, writer); - } - - private void startLine(int level, Writer writer) throws IOException { - for (int i = 0; i < level; i++) - writer.write(INDENT); - } - - private void startGeomTag(String geometryName, Geometry g, Writer writer) - throws IOException { - writer.write("<" - + ((prefix == null || "".equals(prefix)) ? "" : prefix + ":")); - writer.write(geometryName); - writeAttributes(g, writer); - writer.write(">\n"); - writeCustomElements(g, writer); - isRootTag = false; - } - - private void writeAttributes(Geometry geom, Writer writer) throws IOException { - if (geom == null) - return; - if (! isRootTag) - return; - - if (emitNamespace) { - writer.write(" xmlns" - + ((prefix == null || "".equals(prefix)) ? "" : ":"+prefix ) - + "='" + namespace + "'"); - } - if (srsName != null && srsName.length() > 0) { - writer.write(" " + GMLConstants.GML_ATTR_SRSNAME + "='" + srsName + "'"); - // MD - obsoleted -// writer.write(geom.getSRID() + ""); - } - } - - private void writeCustomElements(Geometry geom, Writer writer) throws IOException { - if (geom == null) return; - if (! isRootTag) return; - if (customElements == null) return; - - for (int i = 0; i < customElements.length; i++) { - writer.write(customElements[i]); - writer.write("\n"); - } - } - - private void endGeomTag(String geometryName, Writer writer) - throws IOException { - writer.write("\n"); - } - - private String prefix() - { - if (prefix == null || prefix.length() == 0) - return ""; - return prefix + ":"; - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/gml2/GeometryStrategies.java b/src/main/java/com/vividsolutions/jts/io/gml2/GeometryStrategies.java deleted file mode 100644 index a930fef1c9..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/gml2/GeometryStrategies.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.io.gml2; - -import java.util.*; -import java.util.regex.Pattern; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.gml2.GMLHandler.Handler; -import com.vividsolutions.jts.util.StringUtil; - -/** - * Container for GML2 Geometry parsing strategies which can be represented in JTS. - * - * @author David Zwiers, Vivid Solutions. - */ -public class GeometryStrategies{ - - /** - * This set of strategies is not expected to be used directly outside of this distribution. - * - * The implementation of this class are intended to be used as static function points in C. These strategies should be associated with an element when the element begins. The strategy is utilized at the end of the element to create an object of value to the user. - * - * In this case all the objects are either java.lang.* or JTS Geometry objects - * - * @author David Zwiers, Vivid Solutions. - */ - static interface ParseStrategy{ - /** - * @param arg Value to interpret - * @param gf GeometryFactory - * @return The interpreted value - * @throws SAXException - */ - Object parse(Handler arg, GeometryFactory gf) throws SAXException; - } - - private static HashMap strategies = loadStrategies(); - private static HashMap loadStrategies(){ - HashMap strats = new HashMap(); - - // point - strats.put(GMLConstants.GML_POINT.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()!=1) - throw new SAXException("Cannot create a point without exactly one coordinate"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - Object c = arg.children.get(0); - Point p = null; - if(c instanceof Coordinate){ - p = gf.createPoint((Coordinate)c); - }else{ - p = gf.createPoint((CoordinateSequence)c); - } - if(p.getSRID()!=srid) - p.setSRID(srid); - - return p; - } - }); - - // linestring - strats.put(GMLConstants.GML_LINESTRING.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - LineString ls = null; - if(arg.children.size() == 1){ - // coord set - try{ - CoordinateSequence cs = (CoordinateSequence) arg.children.get(0); - ls = gf.createLineString(cs); - }catch(ClassCastException e){ - throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence",e); - } - }else{ - try{ - Coordinate[] coords = (Coordinate[]) arg.children.toArray(new Coordinate[arg.children.size()]); - ls = gf.createLineString(coords); - }catch(ClassCastException e){ - throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence",e); - } - } - - if(ls.getSRID()!=srid) - ls.setSRID(srid); - - return ls; - } - }); - - // linearring - strats.put(GMLConstants.GML_LINEARRING.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()!=1 && arg.children.size()<4) - throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - LinearRing ls = null; - if(arg.children.size() == 1){ - // coord set - try{ - CoordinateSequence cs = (CoordinateSequence) arg.children.get(0); - ls = gf.createLinearRing(cs); - }catch(ClassCastException e){ - throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence",e); - } - }else{ - try{ - Coordinate[] coords = (Coordinate[]) arg.children.toArray(new Coordinate[arg.children.size()]); - ls = gf.createLinearRing(coords); - }catch(ClassCastException e){ - throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence",e); - } - } - - if(ls.getSRID()!=srid) - ls.setSRID(srid); - - return ls; - } - }); - - // polygon - strats.put(GMLConstants.GML_POLYGON.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a polygon without atleast one linear ring"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - LinearRing outer = (LinearRing) arg.children.get(0); // will be the first - List t = arg.children.size()>1?arg.children.subList(1,arg.children.size()):null; - LinearRing[] inner = t==null?null:(LinearRing[]) t.toArray(new LinearRing[t.size()]); - - Polygon p = gf.createPolygon(outer,inner); - - if(p.getSRID()!=srid) - p.setSRID(srid); - - return p; - } - }); - - // box - strats.put(GMLConstants.GML_BOX.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1 || arg.children.size()>2) - throw new SAXException("Cannot create a box without either two coords or one coordinate sequence"); - -// int srid = getSrid(arg.attrs,gf.getSRID()); - - Envelope box = null; - if(arg.children.size() == 1){ - CoordinateSequence cs = (CoordinateSequence) arg.children.get(0); - box = cs.expandEnvelope(new Envelope()); - }else{ - box = new Envelope((Coordinate)arg.children.get(0),(Coordinate)arg.children.get(1)); - } - - return box; - } - }); - - // multi-point - strats.put(GMLConstants.GML_MULTI_POINT.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a multi-point without atleast one point"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - Point[] pts = (Point[]) arg.children.toArray(new Point[arg.children.size()]); - - MultiPoint mp = gf.createMultiPoint(pts); - - if(mp.getSRID()!=srid) - mp.setSRID(srid); - - return mp; - } - }); - - // multi-linestring - strats.put(GMLConstants.GML_MULTI_LINESTRING.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a multi-linestring without atleast one linestring"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - LineString[] lns = (LineString[]) arg.children.toArray(new LineString[arg.children.size()]); - - MultiLineString mp = gf.createMultiLineString(lns); - - if(mp.getSRID()!=srid) - mp.setSRID(srid); - - return mp; - } - }); - - // multi-poly - strats.put(GMLConstants.GML_MULTI_POLYGON.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a multi-polygon without atleast one polygon"); - - int srid = getSrid(arg.attrs,gf.getSRID()); - - Polygon[] plys = (Polygon[]) arg.children.toArray(new Polygon[arg.children.size()]); - - MultiPolygon mp = gf.createMultiPolygon(plys); - - if(mp.getSRID()!=srid) - mp.setSRID(srid); - - return mp; - } - }); - - // multi-geom - strats.put(GMLConstants.GML_MULTI_GEOMETRY.toLowerCase(),new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.children.size()<1) - throw new SAXException("Cannot create a multi-polygon without atleast one geometry"); - - Geometry[] geoms = (Geometry[]) arg.children.toArray(new Geometry[arg.children.size()]); - - GeometryCollection gc = gf.createGeometryCollection(geoms); - - return gc; - } - }); - - // coordinates - strats.put(GMLConstants.GML_COORDINATES.toLowerCase(),new ParseStrategy(){ - - private WeakHashMap patterns = new WeakHashMap(); - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - // one child, either a coord - // or a coordinate sequence - - if(arg.text == null || "".equals(arg.text)) - throw new SAXException("Cannot create a coordinate sequence without text to parse"); - - String decimal = "."; - String coordSeperator = ","; - String toupleSeperator = " "; - - // get overides from coordinates - if(arg.attrs.getIndex("decimal")>=0) - decimal = arg.attrs.getValue("decimal"); - else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"decimal")>=0) - decimal = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"decimal"); - - if(arg.attrs.getIndex("cs")>=0) - coordSeperator = arg.attrs.getValue("cs"); - else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"cs")>=0) - coordSeperator = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"cs"); - - if(arg.attrs.getIndex("ts")>=0) - toupleSeperator = arg.attrs.getValue("ts"); - else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"ts")>=0) - toupleSeperator = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"ts"); - - // now to start parse - String t = arg.text.toString(); - t = t.replaceAll("\\s"," "); - - Pattern ptn = (Pattern) patterns.get(toupleSeperator); - if(ptn == null){ - String ts = new String(toupleSeperator); - if(ts.indexOf('\\')>-1){ - // need to escape it - ts = ts.replaceAll("\\","\\\\"); - } - if(ts.indexOf('.')>-1){ - // need to escape it - ts = ts.replaceAll("\\.","\\\\."); - } - ptn = Pattern.compile(ts); - patterns.put(toupleSeperator,ptn); - } - String[] touples = ptn.split(t.trim());// t.trim().split(toupleSeperator); - - if(touples.length == 0) - throw new SAXException("Cannot create a coordinate sequence without a touple to parse"); - - // we may have null touples, so calculate the num first - int numNonNullTouples = 0; - for(int i=0;i-1){ - // need to escape it - ts = ts.replaceAll("\\","\\\\"); - } - if(ts.indexOf('.')>-1){ - // need to escape it - ts = ts.replaceAll("\\.","\\\\."); - } - ptn = Pattern.compile(ts); - patterns.put(coordSeperator,ptn); - } - String[] coords = ptn.split(touples[i]);// touples[i].split(coordSeperator); - - int dimIndex = 0; - for(int j=0;j3) - throw new SAXException("Cannot create a coordinate with more than 3 axis"); - - Double[] axis = (Double[]) arg.children.toArray(new Double[arg.children.size()]); - Coordinate c = new Coordinate(); - c.x = axis[0].doubleValue(); - if(axis.length>1) - c.y = axis[1].doubleValue(); - if(axis.length>2) - c.z = axis[2].doubleValue(); - - return c; - } - }); - - ParseStrategy coord_child = new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - if(arg.text == null) - return null; - return new Double((arg.text.toString())); - } - }; - - // coord-x - strats.put(GMLConstants.GML_COORD_X.toLowerCase(),coord_child); - - // coord-y - strats.put(GMLConstants.GML_COORD_Y.toLowerCase(),coord_child); - - // coord-z - strats.put(GMLConstants.GML_COORD_Z.toLowerCase(),coord_child); - - ParseStrategy member = new ParseStrategy(){ - - public Object parse(Handler arg, GeometryFactory gf) throws SAXException { - if(arg.children.size()!=1) - throw new SAXException("Geometry Members may only contain one geometry."); - - // type checking will occur in the parent geom collection. - // may wish to add this in the future - - return arg.children.get(0); - } - }; - // outerBoundary - linear ring member - strats.put(GMLConstants.GML_OUTER_BOUNDARY_IS.toLowerCase(),member); - - // innerBoundary - linear ring member - strats.put(GMLConstants.GML_INNER_BOUNDARY_IS.toLowerCase(),member); - - // point member - strats.put(GMLConstants.GML_POINT_MEMBER.toLowerCase(),member); - - // line string member - strats.put(GMLConstants.GML_LINESTRING_MEMBER.toLowerCase(),member); - - // polygon member - strats.put(GMLConstants.GML_POLYGON_MEMBER.toLowerCase(),member); - - return strats; - } - - static int getSrid(Attributes attrs, int defaultValue){ - String srs = null; - if(attrs.getIndex(GMLConstants.GML_ATTR_SRSNAME)>=0) - srs = attrs.getValue(GMLConstants.GML_ATTR_SRSNAME); - else if(attrs.getIndex(GMLConstants.GML_NAMESPACE,GMLConstants.GML_ATTR_SRSNAME)>=0) - srs = attrs.getValue(GMLConstants.GML_NAMESPACE,GMLConstants.GML_ATTR_SRSNAME); - - if(srs != null){ - srs = srs.trim(); - if(srs != null && !"".equals(srs)){ - try{ - return Integer.parseInt(srs); - }catch(NumberFormatException e){ - // rip out the end, uri's are used here sometimes - int index = srs.lastIndexOf('#'); - if(index > -1) - srs = srs.substring(index); - try{ - return Integer.parseInt(srs); - }catch(NumberFormatException e2){ - // ignore - } - } - } - } - - return defaultValue; - } - - /** - * @param uri Not currently used, included for future work - * @param localName Used to look up an appropriate parse strategy - * @return The ParseStrategy which should be employed - * - * @see ParseStrategy - */ - public static ParseStrategy findStrategy(String uri,String localName){ - return localName == null?null:(ParseStrategy) strategies.get(localName.toLowerCase()); - } -} diff --git a/src/main/java/com/vividsolutions/jts/io/kml/KMLWriter.java b/src/main/java/com/vividsolutions/jts/io/kml/KMLWriter.java deleted file mode 100644 index dcc1b1004d..0000000000 --- a/src/main/java/com/vividsolutions/jts/io/kml/KMLWriter.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.vividsolutions.jts.io.kml; - -import java.io.IOException; -import java.io.Writer; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryCollection; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.LinearRing; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.util.StringUtil; - -/** - * Writes a formatted string containing the KML representation of a JTS - * {@link Geometry}. - * The output is KML fragments which - * can be substituted wherever the KML Geometry abstract element can be used. - *

                    - * Output elements are indented to provide a - * nicely-formatted representation. - * An output line prefix and maximum - * number of coordinates per line can be specified. - *

                    - * The Z ordinate value output can be forced to be a specific value. - * The extrude and altitudeMode modes can be set. - * If set, the corresponding sub-elements will be output. - */ -public class KMLWriter -{ - /** - * The KML standard value clampToGround for use in {@link #setAltitudeMode(String)}. - */ - public static String ALTITUDE_MODE_CLAMPTOGROUND = "clampToGround "; - /** - * The KML standard value relativeToGround for use in {@link #setAltitudeMode(String)}. - */ - public static String ALTITUDE_MODE_RELATIVETOGROUND = "relativeToGround "; - /** - * The KML standard value absolute for use in {@link #setAltitudeMode(String)}. - */ - public static String ALTITUDE_MODE_ABSOLUTE = "absolute"; - - /** - * Writes a Geometry as KML to a string, using - * a specified Z value. - * - * @param geometry the geometry to write - * @param z the Z value to use - * @return a string containing the KML geometry representation - */ - public static String writeGeometry(Geometry geometry, double z) { - KMLWriter writer = new KMLWriter(); - writer.setZ(z); - return writer.write(geometry); - } - - /** - * Writes a Geometry as KML to a string, using - * a specified Z value, precision, extrude flag, - * and altitude mode code. - * - * @param geometry the geometry to write - * @param z the Z value to use - * @param precision the maximum number of decimal places to write - * @param extrude the extrude flag to write - * @param altitudeMode the altitude model code to write - * @return a string containing the KML geometry representation - */ - public static String writeGeometry(Geometry geometry, double z, int precision, - boolean extrude, String altitudeMode) { - KMLWriter writer = new KMLWriter(); - writer.setZ(z); - writer.setPrecision(precision); - writer.setExtrude(extrude); - writer.setAltitudeMode(altitudeMode); - return writer.write(geometry); - } - - private final int INDENT_SIZE = 2; - private static final String COORDINATE_SEPARATOR = ","; - private static final String TUPLE_SEPARATOR = " "; - - private String linePrefix = null; - private int maxCoordinatesPerLine = 5; - private double zVal = Double.NaN; - private boolean extrude = false; - private boolean tesselate; - private String altitudeMode = null; - private DecimalFormat numberFormatter = null; - - /** - * Creates a new writer. - */ - public KMLWriter() { - } - - /** - * Sets a tag string which is prefixed to every emitted text line. - * This can be used to indent the geometry text in a containing document. - * - * @param linePrefix the tag string - */ - public void setLinePrefix(String linePrefix) { - this.linePrefix = linePrefix; - } - - /** - * Sets the maximum number of coordinates to output per line. - * - * @param maxCoordinatesPerLine the maximum number of coordinates to output - */ - public void setMaximumCoordinatesPerLine(int maxCoordinatesPerLine) { - if (maxCoordinatesPerLine <= 0) { - maxCoordinatesPerLine = 1; - return; - } - this.maxCoordinatesPerLine = maxCoordinatesPerLine; - } - - /** - * Sets the Z value to be output for all coordinates. - * This overrides any Z value present in the Geometry coordinates. - * - * @param zVal the Z value to output - */ - public void setZ(double zVal) { - this.zVal = zVal; - } - - /** - * Sets the flag to be output in the extrude element. - * - * @param extrude the extrude flag to output - */ - public void setExtrude(boolean extrude) { - this.extrude = extrude; - } - - /** - * Sets the flag to be output in the tesselate element. - * - * @param tesselate the tesselate flag to output - */ - public void setTesselate(boolean tesselate) { - this.tesselate = tesselate; - } - - /** - * Sets the value output in the altitudeMode element. - * - * @param altitudeMode string representing the altitude mode - */ - public void setAltitudeMode(String altitudeMode) { - this.altitudeMode = altitudeMode; - } - - /** - * Sets the maximum nummber of decimal places to output in ordinate values. - * Useful for limiting output size. - * - * @param precision the number of decimal places to output - */ - public void setPrecision(int precision) { - //this.precision = precision; - if (precision >= 0) - numberFormatter = createFormatter(precision); - } - - /** - * Writes a {@link Geometry} in KML format as a string. - * - * @param geom the geometry to write - * @return a string containing the KML geometry representation - */ - public String write(Geometry geom) { - StringBuffer buf = new StringBuffer(); - write(geom, buf); - return buf.toString(); - } - - /** - * Writes the KML representation of a {@link Geometry} to a {@link Writer}. - * - * @param geometry the geometry to write - * @param writer the Writer to write to - * @throws IOException if an I/O error occurred - */ - public void write(Geometry geometry, Writer writer) throws IOException { - writer.write(write(geometry)); - } - - /** - * Appends the KML representation of a {@link Geometry} to a {@link StringBuffer}. - * - * @param geometry the geometry to write - * @param buf the buffer to write into - */ - public void write(Geometry geometry, StringBuffer buf) { - writeGeometry(geometry, 0, buf); - } - - private void writeGeometry(Geometry g, int level, StringBuffer buf) { - String attributes = ""; - if (g instanceof Point) { - writePoint((Point) g, attributes, level, buf); - } else if (g instanceof LinearRing) { - writeLinearRing((LinearRing) g, attributes, true, level, buf); - } else if (g instanceof LineString) { - writeLineString((LineString) g, attributes, level, buf); - } else if (g instanceof Polygon) { - writePolygon((Polygon) g, attributes, level, buf); - } else if (g instanceof GeometryCollection) { - writeGeometryCollection((GeometryCollection) g, attributes, level, buf); - } - else - throw new IllegalArgumentException("Geometry type not supported: " + g.getGeometryType()); - } - - private void startLine(String text, int level, StringBuffer buf) { - if (linePrefix != null) - buf.append(linePrefix); - buf.append(StringUtil.spaces(INDENT_SIZE * level)); - buf.append(text); - } - - private String geometryTag(String geometryName, String attributes) { - StringBuffer buf = new StringBuffer(); - buf.append("<"); - buf.append(geometryName); - if (attributes != null && attributes.length() > 0) { - buf.append(" "); - buf.append(attributes); - } - buf.append(">"); - return buf.toString(); - } - - private void writeModifiers(int level, StringBuffer buf) - { - if (extrude) { - startLine("1\n", level, buf); - } - if (tesselate) { - startLine("1\n", level, buf); - } - if (altitudeMode != null) { - startLine("" + altitudeMode + "\n", level, buf); - } - } - - private void writePoint(Point p, String attributes, int level, - StringBuffer buf) { - // ... - startLine(geometryTag("Point", attributes) + "\n", level, buf); - writeModifiers(level, buf); - write(new Coordinate[] { p.getCoordinate() }, level + 1, buf); - startLine("\n", level, buf); - } - - private void writeLineString(LineString ls, String attributes, int level, - StringBuffer buf) { - // ... - startLine(geometryTag("LineString", attributes) + "\n", level, buf); - writeModifiers(level, buf); - write(ls.getCoordinates(), level + 1, buf); - startLine("\n", level, buf); - } - - private void writeLinearRing(LinearRing lr, String attributes, - boolean writeModifiers, int level, - StringBuffer buf) { - // ... - startLine(geometryTag("LinearRing", attributes) + "\n", level, buf); - if (writeModifiers) writeModifiers(level, buf); - write(lr.getCoordinates(), level + 1, buf); - startLine("\n", level, buf); - } - - private void writePolygon(Polygon p, String attributes, int level, - StringBuffer buf) { - startLine(geometryTag("Polygon", attributes) + "\n", level, buf); - writeModifiers(level, buf); - - startLine(" \n", level, buf); - writeLinearRing((LinearRing) p.getExteriorRing(), null, false, level + 1, buf); - startLine(" \n", level, buf); - - for (int t = 0; t < p.getNumInteriorRing(); t++) { - startLine(" \n", level, buf); - writeLinearRing((LinearRing) p.getInteriorRingN(t), null, false, level + 1, buf); - startLine(" \n", level, buf); - } - - startLine("\n", level, buf); - } - - private void writeGeometryCollection(GeometryCollection gc, - String attributes, int level, StringBuffer buf) { - startLine("\n", level, buf); - for (int t = 0; t < gc.getNumGeometries(); t++) { - writeGeometry(gc.getGeometryN(t), level + 1, buf); - } - startLine("\n", level, buf); - } - - /** - * Takes a list of coordinates and converts it to KML.
                    - * 2d and 3d aware. Terminates the coordinate output with a newline. - * - * @param cs array of coordinates - */ - private void write(Coordinate[] coords, int level, StringBuffer buf) { - startLine("", level, buf); - - boolean isNewLine = false; - for (int i = 0; i < coords.length; i++) { - if (i > 0) { - buf.append(TUPLE_SEPARATOR); - } - - if (isNewLine) { - startLine(" ", level, buf); - isNewLine = false; - } - - write(coords[i], buf); - - // break output lines to prevent them from getting too long - if ((i + 1) % maxCoordinatesPerLine == 0 && i < coords.length - 1) { - buf.append("\n"); - isNewLine = true; - } - } - buf.append("\n"); - } - - private void write(Coordinate p, StringBuffer buf) { - write(p.x, buf); - buf.append(COORDINATE_SEPARATOR); - write(p.y, buf); - - double z = p.z; - // if altitude was specified directly, use it - if (!Double.isNaN(zVal)) - z = zVal; - - // only write if Z present - // MD - is this right? Or should it always be written? - if (!Double.isNaN(z)) { - buf.append(COORDINATE_SEPARATOR); - write(z, buf); - } - } - - private void write(double num, StringBuffer buf) { - if (numberFormatter != null) - buf.append(numberFormatter.format(num)); - else - buf.append(num); - } - - /** - * Creates the DecimalFormat used to write doubles - * with a sufficient number of decimal places. - * - * @param precisionModel - * the PrecisionModel used to determine the number of - * decimal places to write. - * @return a DecimalFormat that write double s - * without scientific notation. - */ - private static DecimalFormat createFormatter(int precision) { - // specify decimal separator explicitly to avoid problems in other locales - DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - symbols.setDecimalSeparator('.'); - DecimalFormat format = new DecimalFormat("0." - + StringUtil.chars('#', precision), symbols); - format.setDecimalSeparatorAlwaysShown(false); - return format; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/ExtractLineByLocation.java b/src/main/java/com/vividsolutions/jts/linearref/ExtractLineByLocation.java deleted file mode 100644 index 40d217650d..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/ExtractLineByLocation.java +++ /dev/null @@ -1,208 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Extracts the subline of a linear {@link Geometry} between - * two {@link LinearLocation}s on the line. - */ -class ExtractLineByLocation -{ - /** - * Computes the subline of a {@link LineString} between - * two {@link LinearLocation}s on the line. - * If the start location is after the end location, - * the computed linear geometry has reverse orientation to the input line. - * - * @param line the line to use as the baseline - * @param start the start location - * @param end the end location - * @return the extracted subline - */ - public static Geometry extract(Geometry line, LinearLocation start, LinearLocation end) - { - ExtractLineByLocation ls = new ExtractLineByLocation(line); - return ls.extract(start, end); - } - - private Geometry line; - - public ExtractLineByLocation(Geometry line) { - this.line = line; - } - - /** - * Extracts a subline of the input. - * If end < start the linear geometry computed will be reversed. - * - * @param start the start location - * @param end the end location - * @return a linear geometry - */ - public Geometry extract(LinearLocation start, LinearLocation end) - { - if (end.compareTo(start) < 0) { - return reverse(computeLinear(end, start)); - } - return computeLinear(start, end); - } - - private Geometry reverse(Geometry linear) - { - if (linear instanceof LineString) - return ((LineString) linear).reverse(); - if (linear instanceof MultiLineString) - return ((MultiLineString) linear).reverse(); - Assert.shouldNeverReachHere("non-linear geometry encountered"); - return null; - } - /** - * Assumes input is valid (e.g. start <= end) - * - * @param start - * @param end - * @return a linear geometry - */ - private LineString computeLine(LinearLocation start, LinearLocation end) - { - Coordinate[] coordinates = line.getCoordinates(); - CoordinateList newCoordinates = new CoordinateList(); - - int startSegmentIndex = start.getSegmentIndex(); - if (start.getSegmentFraction() > 0.0) - startSegmentIndex += 1; - int lastSegmentIndex = end.getSegmentIndex(); - if (end.getSegmentFraction() == 1.0) - lastSegmentIndex += 1; - if (lastSegmentIndex >= coordinates.length) - lastSegmentIndex = coordinates.length - 1; - // not needed - LinearLocation values should always be correct - //Assert.isTrue(end.getSegmentFraction() <= 1.0, "invalid segment fraction value"); - - if (! start.isVertex()) - newCoordinates.add(start.getCoordinate(line)); - for (int i = startSegmentIndex; i <= lastSegmentIndex; i++) { - newCoordinates.add(coordinates[i]); - } - if (! end.isVertex()) - newCoordinates.add(end.getCoordinate(line)); - - // ensure there is at least one coordinate in the result - if (newCoordinates.size() <= 0) - newCoordinates.add(start.getCoordinate(line)); - - Coordinate[] newCoordinateArray = newCoordinates.toCoordinateArray(); - /** - * Ensure there is enough coordinates to build a valid line. - * Make a 2-point line with duplicate coordinates, if necessary. - * There will always be at least one coordinate in the coordList. - */ - if (newCoordinateArray.length <= 1) { - newCoordinateArray = new Coordinate[] { newCoordinateArray[0], newCoordinateArray[0]}; - } - return line.getFactory().createLineString(newCoordinateArray); - } - - /** - * Assumes input is valid (e.g. start <= end) - * - * @param start - * @param end - * @return a linear geometry - */ - private Geometry computeLinear(LinearLocation start, LinearLocation end) - { - LinearGeometryBuilder builder = new LinearGeometryBuilder(line.getFactory()); - builder.setFixInvalidLines(true); - - if (! start.isVertex()) - builder.add(start.getCoordinate(line)); - - for (LinearIterator it = new LinearIterator(line, start); it.hasNext(); it.next()) { - if (end.compareLocationValues(it.getComponentIndex(), it.getVertexIndex(), 0.0) - < 0) - break; - - Coordinate pt = it.getSegmentStart(); - builder.add(pt); - if (it.isEndOfLine()) - builder.endLine(); - } - if (! end.isVertex()) - builder.add(end.getCoordinate(line)); - - return builder.getGeometry(); - } - - /** - * Computes a valid and normalized location - * compatible with the values in a LinearIterator. - * (I.e. segmentFractions of 1.0 are converted to the next highest coordinate index) - */ - /* - private LinearLocation normalize(LinearLocation loc) - { - int componentIndex = loc.getComponentIndex(); - int segmentIndex = loc.getSegmentIndex(); - double segmentFraction = loc.getSegmentFraction(); - - if (segmentFraction < 0.0) { - segmentFraction = 0.0; - } - if (segmentFraction > 1.0) { - segmentFraction = 1.0; - } - - if (componentIndex < 0) { - componentIndex = 0; - segmentIndex = 0; - segmentFraction = 0.0; - } - if (segmentIndex < 0) { - segmentIndex = 0; - segmentFraction = 0.0; - } - - if (segmentFraction == 1.0) { - segmentFraction = 0.0; - segmentIndex += 1; - } - - return new LinearLocation(componentIndex, segmentIndex, segmentFraction); - } - */ -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LengthIndexOfPoint.java b/src/main/java/com/vividsolutions/jts/linearref/LengthIndexOfPoint.java deleted file mode 100644 index f2f20f877e..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LengthIndexOfPoint.java +++ /dev/null @@ -1,148 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Computes the length index of the point - * on a linear {@link Geometry} nearest a given {@link Coordinate}. - * The nearest point is not necessarily unique; this class - * always computes the nearest point closest to - * the start of the geometry. - */ -class LengthIndexOfPoint -{ - public static double indexOf(Geometry linearGeom, Coordinate inputPt) - { - LengthIndexOfPoint locater = new LengthIndexOfPoint(linearGeom); - return locater.indexOf(inputPt); - } - - public static double indexOfAfter(Geometry linearGeom, Coordinate inputPt, double minIndex) - { - LengthIndexOfPoint locater = new LengthIndexOfPoint(linearGeom); - return locater.indexOfAfter(inputPt, minIndex); - } - - private Geometry linearGeom; - - public LengthIndexOfPoint(Geometry linearGeom) { - this.linearGeom = linearGeom; - } - - /** - * Find the nearest location along a linear {@link Geometry} to a given point. - * - * @param inputPt the coordinate to locate - * @return the location of the nearest point - */ - public double indexOf(Coordinate inputPt) - { - return indexOfFromStart(inputPt, -1.0); - } - - /** - * Finds the nearest index along the linear {@link Geometry} - * to a given {@link Coordinate} - * after the specified minimum index. - * If possible the location returned will be strictly greater than the - * minLocation. - * If this is not possible, the - * value returned will equal minLocation. - * (An example where this is not possible is when - * minLocation = [end of line] ). - * - * @param inputPt the coordinate to locate - * @param minIndex the minimum location for the point location - * @return the location of the nearest point - */ - public double indexOfAfter(Coordinate inputPt, double minIndex) - { - if (minIndex < 0.0) return indexOf(inputPt); - - // sanity check for minIndex at or past end of line - double endIndex = linearGeom.getLength(); - if (endIndex < minIndex) - return endIndex; - - double closestAfter = indexOfFromStart(inputPt, minIndex); - /** - * Return the minDistanceLocation found. - */ - Assert.isTrue(closestAfter >= minIndex, - "computed index is before specified minimum index"); - return closestAfter; - } - - private double indexOfFromStart(Coordinate inputPt, double minIndex) - { - double minDistance = Double.MAX_VALUE; - - double ptMeasure = minIndex; - double segmentStartMeasure = 0.0; - LineSegment seg = new LineSegment(); - LinearIterator it = new LinearIterator(linearGeom); - while (it.hasNext()) { - if (! it.isEndOfLine()) { - seg.p0 = it.getSegmentStart(); - seg.p1 = it.getSegmentEnd(); - double segDistance = seg.distance(inputPt); - double segMeasureToPt = segmentNearestMeasure(seg, inputPt, segmentStartMeasure); - if (segDistance < minDistance - && segMeasureToPt > minIndex) { - ptMeasure = segMeasureToPt; - minDistance = segDistance; - } - segmentStartMeasure += seg.getLength(); - } - it.next(); - } - return ptMeasure; - } - - private double segmentNearestMeasure(LineSegment seg, Coordinate inputPt, - double segmentStartMeasure) - { - // found new minimum, so compute location distance of point - double projFactor = seg.projectionFactor(inputPt); - if (projFactor <= 0.0) - return segmentStartMeasure; - if (projFactor <= 1.0) - return segmentStartMeasure + projFactor * seg.getLength(); - // projFactor > 1.0 - return segmentStartMeasure + seg.getLength(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LengthIndexedLine.java b/src/main/java/com/vividsolutions/jts/linearref/LengthIndexedLine.java deleted file mode 100644 index bf33d281c1..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LengthIndexedLine.java +++ /dev/null @@ -1,272 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * Supports linear referencing along a linear {@link Geometry} - * using the length along the line as the index. - * Negative length values are taken as measured in the reverse direction - * from the end of the geometry. - * Out-of-range index values are handled by clamping - * them to the valid range of values. - * Non-simple lines (i.e. which loop back to cross or touch - * themselves) are supported. - */ -public class LengthIndexedLine -{ - private Geometry linearGeom; - - /** - * Constructs an object which allows a linear {@link Geometry} - * to be linearly referenced using length as an index. - * - * @param linearGeom the linear geometry to reference along - */ - public LengthIndexedLine(Geometry linearGeom) { - this.linearGeom = linearGeom; - } - - /** - * Computes the {@link Coordinate} for the point - * on the line at the given index. - * If the index is out of range the first or last point on the - * line will be returned. - * The Z-ordinate of the computed point will be interpolated from - * the Z-ordinates of the line segment containing it, if they exist. - * - * @param index the index of the desired point - * @return the Coordinate at the given index - */ - public Coordinate extractPoint(double index) - { - LinearLocation loc = LengthLocationMap.getLocation(linearGeom, index); - return loc.getCoordinate(linearGeom); - } - - /** - * Computes the {@link Coordinate} for the point - * on the line at the given index, offset by the given distance. - * If the index is out of range the first or last point on the - * line will be returned. - * The computed point is offset to the left of the line if the offset distance is - * positive, to the right if negative. - * - * The Z-ordinate of the computed point will be interpolated from - * the Z-ordinates of the line segment containing it, if they exist. - * - * @param index the index of the desired point - * @param offsetDistance the distance the point is offset from the segment - * (positive is to the left, negative is to the right) - * @return the Coordinate at the given index - */ - public Coordinate extractPoint(double index, double offsetDistance) - { - LinearLocation loc = LengthLocationMap.getLocation(linearGeom, index); - LinearLocation locLow = loc.toLowest(linearGeom); - return locLow.getSegment(linearGeom).pointAlongOffset(locLow.getSegmentFraction(), offsetDistance); - } - - /** - * Computes the {@link LineString} for the interval - * on the line between the given indices. - * If the endIndex lies before the startIndex, - * the computed geometry is reversed. - * - * @param startIndex the index of the start of the interval - * @param endIndex the index of the end of the interval - * @return the linear interval between the indices - */ - public Geometry extractLine(double startIndex, double endIndex) - { - LocationIndexedLine lil = new LocationIndexedLine(linearGeom); - double startIndex2 = clampIndex(startIndex); - double endIndex2 = clampIndex(endIndex); - // if extracted line is zero-length, resolve start lower as well to ensure they are equal - boolean resolveStartLower = startIndex2 == endIndex2; - LinearLocation startLoc = locationOf(startIndex2, resolveStartLower); -// LinearLocation endLoc = locationOf(endIndex2, true); -// LinearLocation startLoc = locationOf(startIndex2); - LinearLocation endLoc = locationOf(endIndex2); - return ExtractLineByLocation.extract(linearGeom, startLoc, endLoc); - } - - private LinearLocation locationOf(double index) - { - return LengthLocationMap.getLocation(linearGeom, index); - } - - private LinearLocation locationOf(double index, boolean resolveLower) - { - return LengthLocationMap.getLocation(linearGeom, index, resolveLower); - } - - /** - * Computes the minimum index for a point on the line. - * If the line is not simple (i.e. loops back on itself) - * a single point may have more than one possible index. - * In this case, the smallest index is returned. - * - * The supplied point does not necessarily have to lie precisely - * on the line, but if it is far from the line the accuracy and - * performance of this function is not guaranteed. - * Use {@link #project} to compute a guaranteed result for points - * which may be far from the line. - * - * @param pt a point on the line - * @return the minimum index of the point - * - * @see #project(Coordinate) - */ - public double indexOf(Coordinate pt) - { - return LengthIndexOfPoint.indexOf(linearGeom, pt); - } - - /** - * Finds the index for a point on the line - * which is greater than the given index. - * If no such index exists, returns minIndex. - * This method can be used to determine all indexes for - * a point which occurs more than once on a non-simple line. - * It can also be used to disambiguate cases where the given point lies - * slightly off the line and is equidistant from two different - * points on the line. - * - * The supplied point does not necessarily have to lie precisely - * on the line, but if it is far from the line the accuracy and - * performance of this function is not guaranteed. - * Use {@link #project} to compute a guaranteed result for points - * which may be far from the line. - * - * @param pt a point on the line - * @param minIndex the value the returned index must be greater than - * @return the index of the point greater than the given minimum index - * - * @see #project(Coordinate) - */ - public double indexOfAfter(Coordinate pt, double minIndex) - { - return LengthIndexOfPoint.indexOfAfter(linearGeom, pt, minIndex); - } - - /** - * Computes the indices for a subline of the line. - * (The subline must conform to the line; that is, - * all vertices in the subline (except possibly the first and last) - * must be vertices of the line and occcur in the same order). - * - * @param subLine a subLine of the line - * @return a pair of indices for the start and end of the subline. - */ - public double[] indicesOf(Geometry subLine) - { - LinearLocation[] locIndex = LocationIndexOfLine.indicesOf(linearGeom, subLine); - double[] index = new double[] { - LengthLocationMap.getLength(linearGeom, locIndex[0]), - LengthLocationMap.getLength(linearGeom, locIndex[1]) - }; - return index; - } - - - /** - * Computes the index for the closest point on the line to the given point. - * If more than one point has the closest distance the first one along the line - * is returned. - * (The point does not necessarily have to lie precisely on the line.) - * - * @param pt a point on the line - * @return the index of the point - */ - public double project(Coordinate pt) - { - return LengthIndexOfPoint.indexOf(linearGeom, pt); - } - - /** - * Returns the index of the start of the line - * @return the start index - */ - public double getStartIndex() - { - return 0.0; - } - - /** - * Returns the index of the end of the line - * @return the end index - */ - public double getEndIndex() - { - return linearGeom.getLength(); - } - - /** - * Tests whether an index is in the valid index range for the line. - * - * @param index the index to test - * @return true if the index is in the valid range - */ - public boolean isValidIndex(double index) - { - return (index >= getStartIndex() - && index <= getEndIndex()); - } - - /** - * Computes a valid index for this line - * by clamping the given index to the valid range of index values - * - * @return a valid index value - */ - public double clampIndex(double index) - { - double posIndex = positiveIndex(index); - double startIndex = getStartIndex(); - if (posIndex < startIndex) return startIndex; - - double endIndex = getEndIndex(); - if (posIndex > endIndex) return endIndex; - - return posIndex; - } - - private double positiveIndex(double index) - { - if (index >= 0.0) return index; - return linearGeom.getLength() + index; - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LengthLocationMap.java b/src/main/java/com/vividsolutions/jts/linearref/LengthLocationMap.java deleted file mode 100644 index 02d1f5aa8f..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LengthLocationMap.java +++ /dev/null @@ -1,224 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the {@link LinearLocation} for a given length - * along a linear {@link Geometry}. - * Negative lengths are measured in reverse from end of the linear geometry. - * Out-of-range values are clamped. - */ -public class LengthLocationMap -{ - // TODO: cache computed cumulative length for each vertex - // TODO: support user-defined measures - // TODO: support measure index for fast mapping to a location - - /** - * Computes the {@link LinearLocation} for a - * given length along a linear {@link Geometry}. - * - * @param linearGeom the linear geometry to use - * @param length the length index of the location - * @return the {@link LinearLocation} for the length - */ - public static LinearLocation getLocation(Geometry linearGeom, double length) - { - LengthLocationMap locater = new LengthLocationMap(linearGeom); - return locater.getLocation(length); - } - - /** - * Computes the {@link LinearLocation} for a - * given length along a linear {@link Geometry}, - * with control over how the location - * is resolved at component endpoints. - * - * @param linearGeom the linear geometry to use - * @param length the length index of the location - * @param resolveLower if true lengths are resolved to the lowest possible index - * @return the {@link LinearLocation} for the length - */ - public static LinearLocation getLocation(Geometry linearGeom, double length, boolean resolveLower) - { - LengthLocationMap locater = new LengthLocationMap(linearGeom); - return locater.getLocation(length, resolveLower); - } - - /** - * Computes the length for a given {@link LinearLocation} - * on a linear {@link Geometry}. - * - * @param linearGeom the linear geometry to use - * @param loc the {@link LinearLocation} index of the location - * @return the length for the {@link LinearLocation} - */ - public static double getLength(Geometry linearGeom, LinearLocation loc) - { - LengthLocationMap locater = new LengthLocationMap(linearGeom); - return locater.getLength(loc); - } - - private Geometry linearGeom; - - public LengthLocationMap(Geometry linearGeom) - { - this.linearGeom = linearGeom; - } - - /** - * Compute the {@link LinearLocation} corresponding to a length. - * Negative lengths are measured in reverse from end of the linear geometry. - * Out-of-range values are clamped. - * Ambiguous indexes are resolved to the lowest possible location value. - * - * @param length the length index - * @return the corresponding LinearLocation - */ - public LinearLocation getLocation(double length) - { - return getLocation(length, true); - } - - /** - * Compute the {@link LinearLocation} corresponding to a length. - * Negative lengths are measured in reverse from end of the linear geometry. - * Out-of-range values are clamped. - * Ambiguous indexes are resolved to the lowest or highest possible location value, - * depending on the value of resolveLower - * - * @param length the length index - * @return the corresponding LinearLocation - */ - public LinearLocation getLocation(double length, boolean resolveLower) - { - double forwardLength = length; - - // negative values are measured from end of geometry - if (length < 0.0) { - double lineLen = linearGeom.getLength(); - forwardLength = lineLen + length; - } - LinearLocation loc = getLocationForward(forwardLength); - if (resolveLower) { - return loc; - } - return resolveHigher(loc); - } - - private LinearLocation getLocationForward(double length) - { - if (length <= 0.0) - return new LinearLocation(); - - double totalLength = 0.0; - - LinearIterator it = new LinearIterator(linearGeom); - while (it.hasNext()) { - - /** - * Special handling is required for the situation when the - * length references exactly to a component endpoint. - * In this case, the endpoint location of the current component - * is returned, - * rather than the startpoint location of the next component. - * This produces consistent behaviour with the project method. - */ - if (it.isEndOfLine()) { - if (totalLength == length) { - int compIndex = it.getComponentIndex(); - int segIndex = it.getVertexIndex(); - return new LinearLocation(compIndex, segIndex, 0.0); - } - } - else { - Coordinate p0 = it.getSegmentStart(); - Coordinate p1 = it.getSegmentEnd(); - double segLen = p1.distance(p0); - // length falls in this segment - if (totalLength + segLen > length) { - double frac = (length - totalLength) / segLen; - int compIndex = it.getComponentIndex(); - int segIndex = it.getVertexIndex(); - return new LinearLocation(compIndex, segIndex, frac); - } - totalLength += segLen; - } - - it.next(); - } - // length is longer than line - return end location - return LinearLocation.getEndLocation(linearGeom); - } - - private LinearLocation resolveHigher(LinearLocation loc) - { - if (! loc.isEndpoint(linearGeom)) - return loc; - int compIndex = loc.getComponentIndex(); - // if last component can't resolve any higher - if (compIndex >= linearGeom.getNumGeometries() - 1) return loc; - - do { - compIndex++; - } while (compIndex < linearGeom.getNumGeometries() - 1 - && linearGeom.getGeometryN(compIndex).getLength() == 0); - // resolve to next higher location - return new LinearLocation(compIndex, 0, 0.0); - } - - public double getLength(LinearLocation loc) - { - double totalLength = 0.0; - - LinearIterator it = new LinearIterator(linearGeom); - while (it.hasNext()) { - if (! it.isEndOfLine()) { - Coordinate p0 = it.getSegmentStart(); - Coordinate p1 = it.getSegmentEnd(); - double segLen = p1.distance(p0); - // length falls in this segment - if (loc.getComponentIndex() == it.getComponentIndex() - && loc.getSegmentIndex() == it.getVertexIndex()) { - return totalLength + segLen * loc.getSegmentFraction(); - } - totalLength += segLen; - } - it.next(); - } - return totalLength; - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LinearGeometryBuilder.java b/src/main/java/com/vividsolutions/jts/linearref/LinearGeometryBuilder.java deleted file mode 100644 index f7af0ac249..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LinearGeometryBuilder.java +++ /dev/null @@ -1,152 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Builds a linear geometry ({@link LineString} or {@link MultiLineString}) - * incrementally (point-by-point). - * - * @version 1.7 - */ -public class LinearGeometryBuilder -{ - private GeometryFactory geomFact; - private List lines = new ArrayList(); - private CoordinateList coordList = null; - - private boolean ignoreInvalidLines = false; - private boolean fixInvalidLines = false; - - private Coordinate lastPt = null; - - public LinearGeometryBuilder(GeometryFactory geomFact) { - this.geomFact = geomFact; - } - - /** - * Allows invalid lines to be ignored rather than causing Exceptions. - * An invalid line is one which has only one unique point. - * - * @param ignoreInvalidLines true if short lines are to be ignored - */ - public void setIgnoreInvalidLines(boolean ignoreInvalidLines) - { - this.ignoreInvalidLines = ignoreInvalidLines; - } - - /** - * Allows invalid lines to be ignored rather than causing Exceptions. - * An invalid line is one which has only one unique point. - * - * @param fixInvalidLines true if short lines are to be ignored - */ - public void setFixInvalidLines(boolean fixInvalidLines) - { - this.fixInvalidLines = fixInvalidLines; - } - - /** - * Adds a point to the current line. - * - * @param pt the Coordinate to add - */ - public void add(Coordinate pt) - { - add(pt, true); - } - - /** - * Adds a point to the current line. - * - * @param pt the Coordinate to add - */ - public void add(Coordinate pt, boolean allowRepeatedPoints) - { - if (coordList == null) - coordList = new CoordinateList(); - coordList.add(pt, allowRepeatedPoints); - lastPt = pt; - } - - public Coordinate getLastCoordinate() { return lastPt; } - - /** - * Terminate the current LineString. - */ - public void endLine() - { - if (coordList == null) { - return; - } - if (ignoreInvalidLines && coordList.size() < 2) { - coordList = null; - return; - } - Coordinate[] rawPts = coordList.toCoordinateArray(); - Coordinate[] pts = rawPts; - if (fixInvalidLines) - pts = validCoordinateSequence(rawPts); - - coordList = null; - LineString line = null; - try { - line = geomFact.createLineString(pts); - } - catch (IllegalArgumentException ex) { - // exception is due to too few points in line. - // only propagate if not ignoring short lines - if (! ignoreInvalidLines) - throw ex; - } - - if (line != null) lines.add(line); - } - - private Coordinate[] validCoordinateSequence(Coordinate[] pts) - { - if (pts.length >= 2) return pts; - Coordinate[] validPts = new Coordinate[] { pts[0], pts[0]}; - return validPts; - } - - public Geometry getGeometry() - { - // end last line in case it was not done by user - endLine(); - return geomFact.buildGeometry(lines); - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LinearIterator.java b/src/main/java/com/vividsolutions/jts/linearref/LinearIterator.java deleted file mode 100644 index 198d681220..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LinearIterator.java +++ /dev/null @@ -1,209 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * An iterator over the components and coordinates of a linear geometry - * ({@link LineString}s and {@link MultiLineString}s. - * - * The standard usage pattern for a {@link LinearIterator} is: - * - *

                    - * for (LinearIterator it = new LinearIterator(...); it.hasNext(); it.next()) {
                    - *   ...
                    - *   int ci = it.getComponentIndex();   // for example
                    - *   int vi = it.getVertexIndex();      // for example
                    - *   ...
                    - * }
                    - * 
                    - * - * @version 1.7 - */ -public class LinearIterator -{ - private static int segmentEndVertexIndex(LinearLocation loc) - { - if (loc.getSegmentFraction() > 0.0) - return loc.getSegmentIndex() + 1; - return loc.getSegmentIndex(); - } - - private Geometry linearGeom; - private final int numLines; - - /** - * Invariant: currentLine <> null if the iterator is pointing at a valid coordinate - */ - private LineString currentLine; - private int componentIndex = 0; - private int vertexIndex = 0; - - /** - * Creates an iterator initialized to the start of a linear {@link Geometry} - * - * @param linear the linear geometry to iterate over - * @throws IllegalArgumentException if linearGeom is not lineal - */ - public LinearIterator(Geometry linear) { - this(linear, 0, 0); - } - - /** - * Creates an iterator starting at - * a {@link LinearLocation} on a linear {@link Geometry} - * - * @param linear the linear geometry to iterate over - * @param start the location to start at - * @throws IllegalArgumentException if linearGeom is not lineal - */ - public LinearIterator(Geometry linear, LinearLocation start) { - this(linear, start.getComponentIndex(), segmentEndVertexIndex(start)); - } - - /** - * Creates an iterator starting at - * a specified component and vertex in a linear {@link Geometry} - * - * @param linearGeom the linear geometry to iterate over - * @param componentIndex the component to start at - * @param vertexIndex the vertex to start at - * @throws IllegalArgumentException if linearGeom is not lineal - */ - public LinearIterator(Geometry linearGeom, int componentIndex, int vertexIndex) - { - if (! (linearGeom instanceof Lineal)) - throw new IllegalArgumentException("Lineal geometry is required"); - this.linearGeom = linearGeom; - numLines = linearGeom.getNumGeometries(); - this.componentIndex = componentIndex; - this.vertexIndex = vertexIndex; - loadCurrentLine(); - } - - private void loadCurrentLine() - { - if (componentIndex >= numLines) { - currentLine = null; - return; - } - currentLine = (LineString) linearGeom.getGeometryN(componentIndex); - } - - /** - * Tests whether there are any vertices left to iterator over. - * Specifically, hasNext() return true if the - * current state of the iterator represents a valid location - * on the linear geometry. - * - * @return true if there are more vertices to scan - */ - public boolean hasNext() - { - if (componentIndex >= numLines) return false; - if (componentIndex == numLines - 1 - && vertexIndex >= currentLine.getNumPoints()) - return false; - return true; - } - - /** - * Moves the iterator ahead to the next vertex and (possibly) linear component. - */ - public void next() - { - if (! hasNext()) return; - - vertexIndex++; - if (vertexIndex >= currentLine.getNumPoints()) { - componentIndex++; - loadCurrentLine(); - vertexIndex = 0; - } - } - - /** - * Checks whether the iterator cursor is pointing to the - * endpoint of a component {@link LineString}. - * - * @return true if the iterator is at an endpoint - */ - public boolean isEndOfLine() { - if (componentIndex >= numLines) return false; - //LineString currentLine = (LineString) linear.getGeometryN(componentIndex); - if (vertexIndex < currentLine.getNumPoints() - 1) - return false; - return true; - } - - /** - * The component index of the vertex the iterator is currently at. - * @return the current component index - */ - public int getComponentIndex() { return componentIndex; } - - /** - * The vertex index of the vertex the iterator is currently at. - * @return the current vertex index - */ - public int getVertexIndex() { return vertexIndex; } - - /** - * Gets the {@link LineString} component the iterator is current at. - * @return a linestring - */ - public LineString getLine() { return currentLine; } - - /** - * Gets the first {@link Coordinate} of the current segment. - * (the coordinate of the current vertex). - * @return a {@link Coordinate} - */ - public Coordinate getSegmentStart() { return currentLine.getCoordinateN(vertexIndex); } - - /** - * Gets the second {@link Coordinate} of the current segment. - * (the coordinate of the next vertex). - * If the iterator is at the end of a line, null is returned. - * - * @return a {@link Coordinate} or null - */ - public Coordinate getSegmentEnd() - { - if (vertexIndex < getLine().getNumPoints() - 1) - return currentLine.getCoordinateN(vertexIndex + 1); - return null; - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LinearLocation.java b/src/main/java/com/vividsolutions/jts/linearref/LinearLocation.java deleted file mode 100644 index c6a9b7049b..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LinearLocation.java +++ /dev/null @@ -1,484 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * Represents a location along a {@link LineString} or {@link MultiLineString}. - * The referenced geometry is not maintained within - * this location, but must be provided for operations which require it. - * Various methods are provided to manipulate the location value - * and query the geometry it references. - */ -public class LinearLocation - implements Comparable -{ - /** - * Gets a location which refers to the end of a linear {@link Geometry}. - * @param linear the linear geometry - * @return a new LinearLocation - */ - public static LinearLocation getEndLocation(Geometry linear) - { - // assert: linear is LineString or MultiLineString - LinearLocation loc = new LinearLocation(); - loc.setToEnd(linear); - return loc; - } - - /** - * Computes the {@link Coordinate} of a point a given fraction - * along the line segment (p0, p1). - * If the fraction is greater than 1.0 the last - * point of the segment is returned. - * If the fraction is less than or equal to 0.0 the first point - * of the segment is returned. - * The Z ordinate is interpolated from the Z-ordinates of the given points, - * if they are specified. - * - * @param p0 the first point of the line segment - * @param p1 the last point of the line segment - * @param frac the length to the desired point - * @return the Coordinate of the desired point - */ - public static Coordinate pointAlongSegmentByFraction(Coordinate p0, Coordinate p1, double frac) - { - if (frac <= 0.0) return p0; - if (frac >= 1.0) return p1; - - double x = (p1.x - p0.x) * frac + p0.x; - double y = (p1.y - p0.y) * frac + p0.y; - // interpolate Z value. If either input Z is NaN, result z will be NaN as well. - double z = (p1.z - p0.z) * frac + p0.z; - return new Coordinate(x, y, z); - } - - private int componentIndex = 0; - private int segmentIndex = 0; - private double segmentFraction = 0.0; - - /** - * Creates a location referring to the start of a linear geometry - */ - public LinearLocation() - { - } - - public LinearLocation(int segmentIndex, double segmentFraction) { - this(0, segmentIndex, segmentFraction); - } - - public LinearLocation(int componentIndex, int segmentIndex, double segmentFraction) - { - this.componentIndex = componentIndex; - this.segmentIndex = segmentIndex; - this.segmentFraction = segmentFraction; - normalize(); - } - - private LinearLocation(int componentIndex, int segmentIndex, double segmentFraction, boolean doNormalize) - { - this.componentIndex = componentIndex; - this.segmentIndex = segmentIndex; - this.segmentFraction = segmentFraction; - if (doNormalize) - normalize(); - } - - /** - * Creates a new location equal to a given one. - * - * @param loc a LinearLocation - */ - public LinearLocation(LinearLocation loc) - { - this.componentIndex = loc.componentIndex; - this.segmentIndex = loc.segmentIndex; - this.segmentFraction = loc.segmentFraction; - } - - /** - * Ensures the individual values are locally valid. - * Does not ensure that the indexes are valid for - * a particular linear geometry. - * - * @see clamp - */ - private void normalize() - { - if (segmentFraction < 0.0) { - segmentFraction = 0.0; - } - if (segmentFraction > 1.0) { - segmentFraction = 1.0; - } - - if (componentIndex < 0) { - componentIndex = 0; - segmentIndex = 0; - segmentFraction = 0.0; - } - if (segmentIndex < 0) { - segmentIndex = 0; - segmentFraction = 0.0; - } - if (segmentFraction == 1.0) { - segmentFraction = 0.0; - segmentIndex += 1; - } - } - - - /** - * Ensures the indexes are valid for a given linear {@link Geometry}. - * - * @param linear a linear geometry - */ - public void clamp(Geometry linear) - { - if (componentIndex >= linear.getNumGeometries()) { - setToEnd(linear); - return; - } - if (segmentIndex >= linear.getNumPoints()) { - LineString line = (LineString) linear.getGeometryN(componentIndex); - segmentIndex = line.getNumPoints() - 1; - segmentFraction = 1.0; - } - } - /** - * Snaps the value of this location to - * the nearest vertex on the given linear {@link Geometry}, - * if the vertex is closer than minDistance. - * - * @param linearGeom a linear geometry - * @param minDistance the minimum allowable distance to a vertex - */ - public void snapToVertex(Geometry linearGeom, double minDistance) - { - if (segmentFraction <= 0.0 || segmentFraction >= 1.0) - return; - double segLen = getSegmentLength(linearGeom); - double lenToStart = segmentFraction * segLen; - double lenToEnd = segLen - lenToStart; - if (lenToStart <= lenToEnd && lenToStart < minDistance) { - segmentFraction = 0.0; - } - else if (lenToEnd <= lenToStart && lenToEnd < minDistance) { - segmentFraction = 1.0; - } - } - - /** - * Gets the length of the segment in the given - * Geometry containing this location. - * - * @param linearGeom a linear geometry - * @return the length of the segment - */ - public double getSegmentLength(Geometry linearGeom) - { - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - - // ensure segment index is valid - int segIndex = segmentIndex; - if (segmentIndex >= lineComp.getNumPoints() - 1) - segIndex = lineComp.getNumPoints() - 2; - - Coordinate p0 = lineComp.getCoordinateN(segIndex); - Coordinate p1 = lineComp.getCoordinateN(segIndex + 1); - return p0.distance(p1); - } - - /** - * Sets the value of this location to - * refer to the end of a linear geometry. - * - * @param linear the linear geometry to use to set the end - */ - public void setToEnd(Geometry linear) - { - componentIndex = linear.getNumGeometries() - 1; - LineString lastLine = (LineString) linear.getGeometryN(componentIndex); - segmentIndex = lastLine.getNumPoints() - 1; - segmentFraction = 1.0; - } - - /** - * Gets the component index for this location. - * - * @return the component index - */ - public int getComponentIndex() { return componentIndex; } - - /** - * Gets the segment index for this location - * - * @return the segment index - */ - public int getSegmentIndex() { return segmentIndex; } - - /** - * Gets the segment fraction for this location - * - * @return the segment fraction - */ - public double getSegmentFraction() { return segmentFraction; } - - /** - * Tests whether this location refers to a vertex - * - * @return true if the location is a vertex - */ - public boolean isVertex() - { - return segmentFraction <= 0.0 || segmentFraction >= 1.0; - } - - /** - * Gets the {@link Coordinate} along the - * given linear {@link Geometry} which is - * referenced by this location. - * - * @param linearGeom the linear geometry referenced by this location - * @return the Coordinate at the location - */ - public Coordinate getCoordinate(Geometry linearGeom) - { - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - Coordinate p0 = lineComp.getCoordinateN(segmentIndex); - if (segmentIndex >= lineComp.getNumPoints() - 1) - return p0; - Coordinate p1 = lineComp.getCoordinateN(segmentIndex + 1); - return pointAlongSegmentByFraction(p0, p1, segmentFraction); - } - - /** - * Gets a {@link LineSegment} representing the segment of the - * given linear {@link Geometry} which contains this location. - * - * @param linearGeom a linear geometry - * @return the LineSegment containing the location - */ - public LineSegment getSegment(Geometry linearGeom) - { - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - Coordinate p0 = lineComp.getCoordinateN(segmentIndex); - // check for endpoint - return last segment of the line if so - if (segmentIndex >= lineComp.getNumPoints() - 1) { - Coordinate prev = lineComp.getCoordinateN(lineComp.getNumPoints() - 2); - return new LineSegment(prev, p0); - } - Coordinate p1 = lineComp.getCoordinateN(segmentIndex + 1); - return new LineSegment(p0, p1); - } - - /** - * Tests whether this location refers to a valid - * location on the given linear {@link Geometry}. - * - * @param linearGeom a linear geometry - * @return true if this location is valid - */ - public boolean isValid(Geometry linearGeom) - { - if (componentIndex < 0 || componentIndex >= linearGeom.getNumGeometries()) - return false; - - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - if (segmentIndex < 0 || segmentIndex > lineComp.getNumPoints()) - return false; - if (segmentIndex == lineComp.getNumPoints() && segmentFraction != 0.0) - return false; - - if (segmentFraction < 0.0 || segmentFraction > 1.0) - return false; - return true; - } - - /** - * Compares this object with the specified object for order. - * - *@param o the LineStringLocation with which this Coordinate - * is being compared - *@return a negative integer, zero, or a positive integer as this LineStringLocation - * is less than, equal to, or greater than the specified LineStringLocation - */ - public int compareTo(Object o) { - LinearLocation other = (LinearLocation) o; - // compare component indices - if (componentIndex < other.componentIndex) return -1; - if (componentIndex > other.componentIndex) return 1; - // compare segments - if (segmentIndex < other.segmentIndex) return -1; - if (segmentIndex > other.segmentIndex) return 1; - // same segment, so compare segment fraction - if (segmentFraction < other.segmentFraction) return -1; - if (segmentFraction > other.segmentFraction) return 1; - // same location - return 0; - } - - /** - * Compares this object with the specified index values for order. - * - * @param componentIndex1 a component index - * @param segmentIndex1 a segment index - * @param segmentFraction1 a segment fraction - * @return a negative integer, zero, or a positive integer as this LineStringLocation - * is less than, equal to, or greater than the specified locationValues - */ - public int compareLocationValues(int componentIndex1, int segmentIndex1, double segmentFraction1) { - // compare component indices - if (componentIndex < componentIndex1) return -1; - if (componentIndex > componentIndex1) return 1; - // compare segments - if (segmentIndex < segmentIndex1) return -1; - if (segmentIndex > segmentIndex1) return 1; - // same segment, so compare segment fraction - if (segmentFraction < segmentFraction1) return -1; - if (segmentFraction > segmentFraction1) return 1; - // same location - return 0; - } - - /** - * Compares two sets of location values for order. - * - * @param componentIndex0 a component index - * @param segmentIndex0 a segment index - * @param segmentFraction0 a segment fraction - * @param componentIndex1 another component index - * @param segmentIndex1 another segment index - * @param segmentFraction1 another segment fraction - *@return a negative integer, zero, or a positive integer - * as the first set of location values - * is less than, equal to, or greater than the second set of locationValues - */ - public static int compareLocationValues( - int componentIndex0, int segmentIndex0, double segmentFraction0, - int componentIndex1, int segmentIndex1, double segmentFraction1) - { - // compare component indices - if (componentIndex0 < componentIndex1) return -1; - if (componentIndex0 > componentIndex1) return 1; - // compare segments - if (segmentIndex0 < segmentIndex1) return -1; - if (segmentIndex0 > segmentIndex1) return 1; - // same segment, so compare segment fraction - if (segmentFraction0 < segmentFraction1) return -1; - if (segmentFraction0 > segmentFraction1) return 1; - // same location - return 0; - } - - /** - * Tests whether two locations - * are on the same segment in the parent {@link Geometry}. - * - * @param loc a location on the same geometry - * @return true if the locations are on the same segment of the parent geometry - */ - public boolean isOnSameSegment(LinearLocation loc) - { - if (componentIndex != loc.componentIndex) return false; - if (segmentIndex == loc.segmentIndex) return true; - if (loc.segmentIndex - segmentIndex == 1 - && loc.segmentFraction == 0.0) - return true; - if (segmentIndex - loc.segmentIndex == 1 - && segmentFraction == 0.0) - return true; - return false; - } - - /** - * Tests whether this location is an endpoint of - * the linear component it refers to. - * - * @param linearGeom the linear geometry referenced by this location - * @return true if the location is a component endpoint - */ - public boolean isEndpoint(Geometry linearGeom) - { - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - // check for endpoint - int nseg = lineComp.getNumPoints() - 1; - return segmentIndex >= nseg - || (segmentIndex == nseg && segmentFraction >= 1.0); - } - - /** - * Converts a linear location to the lowest equivalent location index. - * The lowest index has the lowest possible component and segment indices. - *

                    - * Specifically: - *

                      - *
                    • if the location point is an endpoint, a location value is returned as (nseg-1, 1.0) - *
                    • if the location point is ambiguous (i.e. an endpoint and a startpoint), the lowest endpoint location is returned - *
                    - * If the location index is already the lowest possible value, the original location is returned. - * - * @param linearGeom the linear geometry referenced by this location - * @return the lowest equivalent location - */ - public LinearLocation toLowest(Geometry linearGeom) - { - // TODO: compute lowest component index - LineString lineComp = (LineString) linearGeom.getGeometryN(componentIndex); - int nseg = lineComp.getNumPoints() - 1; - // if not an endpoint can be returned directly - if (segmentIndex < nseg) return this; - return new LinearLocation(componentIndex, nseg, 1.0, false); - } - - /** - * Copies this location - * - * @return a copy of this location - */ - public Object clone() - { - return new LinearLocation(componentIndex, segmentIndex, segmentFraction); - } - - public String toString() - { - return "LinearLoc[" - + componentIndex + ", " - + segmentIndex + ", " - + segmentFraction + "]"; - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfLine.java b/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfLine.java deleted file mode 100644 index c29a20ebb2..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfLine.java +++ /dev/null @@ -1,85 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * Determines the location of a subline along a linear {@link Geometry}. - * The location is reported as a pair of {@link LinearLocation}s. - *

                    - * Note: Currently this algorithm is not guaranteed to - * return the correct substring in some situations where - * an endpoint of the test line occurs more than once in the input line. - * (However, the common case of a ring is always handled correctly). - */ -class LocationIndexOfLine -{ - /** - * MD - this algorithm has been extracted into a class - * because it is intended to validate that the subline truly is a subline, - * and also to use the internal vertex information to unambiguously locate the subline. - */ - public static LinearLocation[] indicesOf(Geometry linearGeom, Geometry subLine) - { - LocationIndexOfLine locater = new LocationIndexOfLine(linearGeom); - return locater.indicesOf(subLine); - } - - private Geometry linearGeom; - - public LocationIndexOfLine(Geometry linearGeom) { - this.linearGeom = linearGeom; - } - - public LinearLocation[] indicesOf(Geometry subLine) - { - Coordinate startPt = ((LineString) subLine.getGeometryN(0)).getCoordinateN(0); - LineString lastLine = (LineString) subLine.getGeometryN(subLine.getNumGeometries() - 1); - Coordinate endPt = lastLine.getCoordinateN(lastLine.getNumPoints() - 1); - - LocationIndexOfPoint locPt = new LocationIndexOfPoint(linearGeom); - LinearLocation[] subLineLoc = new LinearLocation[2]; - subLineLoc[0] = locPt.indexOf(startPt); - - // check for case where subline is zero length - if (subLine.getLength() == 0.0) { - subLineLoc[1] = (LinearLocation) subLineLoc[0].clone(); - } - else { - subLineLoc[1] = locPt.indexOfAfter(endPt, subLineLoc[0]); - } - return subLineLoc; - } -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfPoint.java b/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfPoint.java deleted file mode 100644 index 19475a54c2..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexOfPoint.java +++ /dev/null @@ -1,178 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Computes the {@link LinearLocation} of the point - * on a linear {@link Geometry} nearest a given {@link Coordinate}. - * The nearest point is not necessarily unique; this class - * always computes the nearest point closest to - * the start of the geometry. - */ -class LocationIndexOfPoint -{ - public static LinearLocation indexOf(Geometry linearGeom, Coordinate inputPt) - { - LocationIndexOfPoint locater = new LocationIndexOfPoint(linearGeom); - return locater.indexOf(inputPt); - } - - public static LinearLocation indexOfAfter(Geometry linearGeom, Coordinate inputPt, LinearLocation minIndex) - { - LocationIndexOfPoint locater = new LocationIndexOfPoint(linearGeom); - return locater.indexOfAfter(inputPt, minIndex); - } - - private Geometry linearGeom; - - public LocationIndexOfPoint(Geometry linearGeom) { - this.linearGeom = linearGeom; - } - - /** - * Find the nearest location along a linear {@link Geometry} to a given point. - * - * @param inputPt the coordinate to locate - * @return the location of the nearest point - */ - public LinearLocation indexOf(Coordinate inputPt) - { - return indexOfFromStart(inputPt, null); - } - - /** - * Find the nearest {@link LinearLocation} along the linear {@link Geometry} - * to a given {@link Coordinate} - * after the specified minimum {@link LinearLocation}. - * If possible the location returned will be strictly greater than the - * minLocation. - * If this is not possible, the - * value returned will equal minLocation. - * (An example where this is not possible is when - * minLocation = [end of line] ). - * - * @param inputPt the coordinate to locate - * @param minIndex the minimum location for the point location - * @return the location of the nearest point - */ - public LinearLocation indexOfAfter(Coordinate inputPt, LinearLocation minIndex) - { - if (minIndex == null) return indexOf(inputPt); - - // sanity check for minLocation at or past end of line - LinearLocation endLoc = LinearLocation.getEndLocation(linearGeom); - if (endLoc.compareTo(minIndex) <= 0) - return endLoc; - - LinearLocation closestAfter = indexOfFromStart(inputPt, minIndex); - /** - * Return the minDistanceLocation found. - * This will not be null, since it was initialized to minLocation - */ - Assert.isTrue(closestAfter.compareTo(minIndex) >= 0, - "computed location is before specified minimum location"); - return closestAfter; - } - - private LinearLocation indexOfFromStart(Coordinate inputPt, LinearLocation minIndex) - { - double minDistance = Double.MAX_VALUE; - int minComponentIndex = 0; - int minSegmentIndex = 0; - double minFrac = -1.0; - - LineSegment seg = new LineSegment(); - for (LinearIterator it = new LinearIterator(linearGeom); - it.hasNext(); it.next()) { - if (! it.isEndOfLine()) { - seg.p0 = it.getSegmentStart(); - seg.p1 = it.getSegmentEnd(); - double segDistance = seg.distance(inputPt); - double segFrac = seg.segmentFraction(inputPt); - - int candidateComponentIndex = it.getComponentIndex(); - int candidateSegmentIndex = it.getVertexIndex(); - if (segDistance < minDistance) { - // ensure after minLocation, if any - if (minIndex == null || - minIndex.compareLocationValues( - candidateComponentIndex, candidateSegmentIndex, segFrac) - < 0 - ) { - // otherwise, save this as new minimum - minComponentIndex = candidateComponentIndex; - minSegmentIndex = candidateSegmentIndex; - minFrac = segFrac; - minDistance = segDistance; - } - } - } - } - if (minDistance == Double.MAX_VALUE) { - // no minimum was found past minLocation, so return it - return new LinearLocation(minIndex); - } - // otherwise, return computed location - LinearLocation loc = new LinearLocation(minComponentIndex, minSegmentIndex, minFrac); - return loc; - } - - /** - * Computes the fraction of distance (in [0.0, 1.0]) - * that a point occurs along a line segment. - * If the point is beyond either ends of the line segment, - * the closest fractional value (0.0 or 1.0) is returned. - * - * @param seg the line segment to use - * @param inputPt the point - * @return the fraction along the line segment the point occurs - */ - /* - // MD - no longer needed - private static double segmentFraction( - LineSegment seg, - Coordinate inputPt) - { - double segFrac = seg.projectionFactor(inputPt); - if (segFrac < 0.0) - segFrac = 0.0; - else if (segFrac > 1.0) - segFrac = 1.0; - return segFrac; - } - */ -} diff --git a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexedLine.java b/src/main/java/com/vividsolutions/jts/linearref/LocationIndexedLine.java deleted file mode 100644 index 2dbcb711ae..0000000000 --- a/src/main/java/com/vividsolutions/jts/linearref/LocationIndexedLine.java +++ /dev/null @@ -1,232 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.linearref; - -import com.vividsolutions.jts.geom.*; - -/** - * Supports linear referencing - * along a linear {@link Geometry} - * using {@link LinearLocation}s as the index. - */ -public class LocationIndexedLine -{ - private Geometry linearGeom; - - /** - * Constructs an object which allows linear referencing along - * a given linear {@link Geometry}. - * - * @param linearGeom the linear geometry to reference along - */ - public LocationIndexedLine(Geometry linearGeom) - { - this.linearGeom = linearGeom; - checkGeometryType(); - } - - private void checkGeometryType() - { - if (! (linearGeom instanceof LineString || linearGeom instanceof MultiLineString)) - throw new IllegalArgumentException("Input geometry must be linear"); - } - /** - * Computes the {@link Coordinate} for the point - * on the line at the given index. - * If the index is out of range the first or last point on the - * line will be returned. - * The Z-ordinate of the computed point will be interpolated from - * the Z-ordinates of the line segment containing it, if they exist. - * - * @param index the index of the desired point - * @return the Coordinate at the given index - */ - public Coordinate extractPoint(LinearLocation index) - { - return index.getCoordinate(linearGeom); - } - - /** - * Computes the {@link Coordinate} for the point - * on the line at the given index, offset by the given distance. - * If the index is out of range the first or last point on the - * line will be returned. - * The computed point is offset to the left of the line if the offset distance is - * positive, to the right if negative. - * - * The Z-ordinate of the computed point will be interpolated from - * the Z-ordinates of the line segment containing it, if they exist. - * - * @param index the index of the desired point - * @param offsetDistance the distance the point is offset from the segment - * (positive is to the left, negative is to the right) - * @return the Coordinate at the given index - */ - public Coordinate extractPoint(LinearLocation index, double offsetDistance) - { - LinearLocation indexLow = index.toLowest(linearGeom); - return indexLow.getSegment(linearGeom).pointAlongOffset(indexLow.getSegmentFraction(), offsetDistance); - } - - /** - * Computes the {@link LineString} for the interval - * on the line between the given indices. - * If the start location is after the end location, - * the computed linear geometry has reverse orientation to the input line. - * - * @param startIndex the index of the start of the interval - * @param endIndex the index of the end of the interval - * @return the linear geometry between the indices - */ - public Geometry extractLine(LinearLocation startIndex, LinearLocation endIndex) - { - return ExtractLineByLocation.extract(linearGeom, startIndex, endIndex); - } - - /** - * Computes the index for a given point on the line. - *

                    - * The supplied point does not necessarily have to lie precisely - * on the line, but if it is far from the line the accuracy and - * performance of this function is not guaranteed. - * Use {@link #project} to compute a guaranteed result for points - * which may be far from the line. - * - * @param pt a point on the line - * @return the index of the point - * @see #project(Coordinate) - */ - public LinearLocation indexOf(Coordinate pt) - { - return LocationIndexOfPoint.indexOf(linearGeom, pt); - } - - /** - * Finds the index for a point on the line - * which is greater than the given index. - * If no such index exists, returns minIndex. - * This method can be used to determine all indexes for - * a point which occurs more than once on a non-simple line. - * It can also be used to disambiguate cases where the given point lies - * slightly off the line and is equidistant from two different - * points on the line. - * - * The supplied point does not necessarily have to lie precisely - * on the line, but if it is far from the line the accuracy and - * performance of this function is not guaranteed. - * Use {@link #project} to compute a guaranteed result for points - * which may be far from the line. - * - * @param pt a point on the line - * @param minIndex the value the returned index must be greater than - * @return the index of the point greater than the given minimum index - * - * @see #project(Coordinate) - */ - public LinearLocation indexOfAfter(Coordinate pt, LinearLocation minIndex) - { - return LocationIndexOfPoint.indexOfAfter(linearGeom, pt, minIndex); - } - - - /** - * Computes the indices for a subline of the line. - * (The subline must conform to the line; that is, - * all vertices in the subline (except possibly the first and last) - * must be vertices of the line and occcur in the same order). - * - * @param subLine a subLine of the line - * @return a pair of indices for the start and end of the subline. - */ - public LinearLocation[] indicesOf(Geometry subLine) - { - return LocationIndexOfLine.indicesOf(linearGeom, subLine); - } - - /** - * Computes the index for the closest point on the line to the given point. - * If more than one point has the closest distance the first one along the line - * is returned. - * (The point does not necessarily have to lie precisely on the line.) - * - * @param pt a point on the line - * @return the index of the point - */ - public LinearLocation project(Coordinate pt) - { - return LocationIndexOfPoint.indexOf(linearGeom, pt); - } - - /** - * Returns the index of the start of the line - * @return the location index - */ - public LinearLocation getStartIndex() - { - return new LinearLocation(); - } - - /** - * Returns the index of the end of the line - * @return the location index - */ - public LinearLocation getEndIndex() - { - return LinearLocation.getEndLocation(linearGeom); - } - - /** - * Tests whether an index is in the valid index range for the line. - * - * @param index the index to test - * @return true if the index is in the valid range - */ - public boolean isValidIndex(LinearLocation index) - { - return index.isValid(linearGeom); - } - - /** - * Computes a valid index for this line - * by clamping the given index to the valid range of index values - * - * @return a valid index value - */ - public LinearLocation clampIndex(LinearLocation index) - { - LinearLocation loc = (LinearLocation) index.clone(); - loc.clamp(linearGeom); - return loc; - } -} diff --git a/src/main/java/com/vividsolutions/jts/math/DD.java b/src/main/java/com/vividsolutions/jts/math/DD.java deleted file mode 100644 index d5a9a0a77b..0000000000 --- a/src/main/java/com/vividsolutions/jts/math/DD.java +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.math; - -import java.io.*; - -/** - * Implements extended-precision floating-point numbers - * which maintain 106 bits (approximately 30 decimal digits) of precision. - *

                    - * A DoubleDouble uses a representation containing two double-precision values. - * A number x is represented as a pair of doubles, x.hi and x.lo, - * such that the number represented by x is x.hi + x.lo, where - *

                    - *    |x.lo| <= 0.5*ulp(x.hi)
                    - * 
                    - * and ulp(y) means "unit in the last place of y". - * The basic arithmetic operations are implemented using - * convenient properties of IEEE-754 floating-point arithmetic. - *

                    - * The range of values which can be represented is the same as in IEEE-754. - * The precision of the representable numbers - * is twice as great as IEEE-754 double precision. - *

                    - * The correctness of the arithmetic algorithms relies on operations - * being performed with standard IEEE-754 double precision and rounding. - * This is the Java standard arithmetic model, but for performance reasons - * Java implementations are not - * constrained to using this standard by default. - * Some processors (notably the Intel Pentium architecure) perform - * floating point operations in (non-IEEE-754-standard) extended-precision. - * A JVM implementation may choose to use the non-standard extended-precision - * as its default arithmetic mode. - * To prevent this from happening, this code uses the - * Java strictfp modifier, - * which forces all operations to take place in the standard IEEE-754 rounding model. - *

                    - * The API provides both a set of value-oriented operations - * and a set of mutating operations. - * Value-oriented operations treat DoubleDouble values as - * immutable; operations on them return new objects carrying the result - * of the operation. This provides a simple and safe semantics for - * writing DoubleDouble expressions. However, there is a performance - * penalty for the object allocations required. - * The mutable interface updates object values in-place. - * It provides optimum memory performance, but requires - * care to ensure that aliasing errors are not created - * and constant values are not changed. - *

                    - * For example, the following code example constructs three DD instances: - * two to hold the input values and one to hold the result of the addition. - *

                    - *     DD a = new DD(2.0);
                    - *     DD b = new DD(3.0);
                    - *     DD c = a.add(b);
                    - * 
                    - * In contrast, the following approach uses only one object: - *
                    - *     DD a = new DD(2.0);
                    - *     a.selfAdd(3.0);
                    - * 
                    - *

                    - * This implementation uses algorithms originally designed variously by - * Knuth, Kahan, Dekker, and Linnainmaa. - * Douglas Priest developed the first C implementation of these techniques. - * Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al. - * - *

                    References

                    - *
                      - *
                    • Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, - * in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic, - * IEEE Computer Society Press, Los Alamitos, Calif., 1991. - *
                    • Yozo Hida, Xiaoye S. Li and David H. Bailey, - * Quad-Double Arithmetic: Algorithms, Implementation, and Application, - * manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996. - *
                    • David Bailey, High Precision Software Directory; - * http://crd.lbl.gov/~dhbailey/mpdist/index.html - *
                    - * - * - * @author Martin Davis - * - */ -public strictfp final class DD - implements Serializable, Comparable, Cloneable -{ - /** - * The value nearest to the constant Pi. - */ - public static final DD PI = new DD( - 3.141592653589793116e+00, - 1.224646799147353207e-16); - - /** - * The value nearest to the constant 2 * Pi. - */ - public static final DD TWO_PI = new DD( - 6.283185307179586232e+00, - 2.449293598294706414e-16); - - /** - * The value nearest to the constant Pi / 2. - */ - public static final DD PI_2 = new DD( - 1.570796326794896558e+00, - 6.123233995736766036e-17); - - /** - * The value nearest to the constant e (the natural logarithm base). - */ - public static final DD E = new DD( - 2.718281828459045091e+00, - 1.445646891729250158e-16); - - /** - * A value representing the result of an operation which does not return a valid number. - */ - public static final DD NaN = new DD(Double.NaN, Double.NaN); - - /** - * The smallest representable relative difference between two {link @ DoubleDouble} values - */ - public static final double EPS = 1.23259516440783e-32; /* = 2^-106 */ - - private static DD createNaN() - { - return new DD(Double.NaN, Double.NaN); - } - - /** - * Converts the string argument to a DoubleDouble number. - * - * @param str a string containing a representation of a numeric value - * @return the extended precision version of the value - * @throws NumberFormatException if s is not a valid representation of a number - */ - public static DD valueOf(String str) - throws NumberFormatException - { - return parse(str); - } - - /** - * Converts the double argument to a DoubleDouble number. - * - * @param x a numeric value - * @return the extended precision version of the value - */ - public static DD valueOf(double x) { return new DD(x); } - - /** - * The value to split a double-precision value on during multiplication - */ - private static final double SPLIT = 134217729.0D; // 2^27+1, for IEEE double - - /** - * The high-order component of the double-double precision value. - */ - private double hi = 0.0; - - /** - * The low-order component of the double-double precision value. - */ - private double lo = 0.0; - - /** - * Creates a new DoubleDouble with value 0.0. - */ - public DD() - { - init(0.0); - } - - /** - * Creates a new DoubleDouble with value x. - * - * @param x the value to initialize - */ - public DD(double x) - { - init(x); - } - - /** - * Creates a new DoubleDouble with value (hi, lo). - * - * @param hi the high-order component - * @param lo the high-order component - */ - public DD(double hi, double lo) - { - init(hi, lo); - } - - /** - * Creates a new DoubleDouble with value equal to the argument. - * - * @param dd the value to initialize - */ - public DD(DD dd) - { - init(dd); - } - - /** - * Creates a new DoubleDouble with value equal to the argument. - * - * @param str the value to initialize by - * @throws NumberFormatException if str is not a valid representation of a number - */ - public DD(String str) - throws NumberFormatException - { - this(parse(str)); - } - - /** - * Creates a new DoubleDouble with the value of the argument. - * - * @param dd the DoubleDouble value to copy - * @return a copy of the input value - */ - public static DD copy(DD dd) - { - return new DD(dd); - } - - /** - * Creates and returns a copy of this value. - * - * @return a copy of this value - */ - public Object clone() - { - try { - return super.clone(); - } - catch (CloneNotSupportedException ex) { - // should never reach here - return null; - } - } - - private final void init(double x) - { - this.hi = x; - this.lo = 0.0; - } - - private final void init(double hi, double lo) - { - this.hi = hi; - this.lo = lo; - } - - private final void init(DD dd) - { - hi = dd.hi; - lo = dd.lo; - } - - /* - double getHighComponent() { return hi; } - - double getLowComponent() { return lo; } - */ - - // Testing only - should not be public - /* - public void RENORM() - { - double s = hi + lo; - double err = lo - (s - hi); - hi = s; - lo = err; - } - */ - - /** - * Set the value for the DD object. This method supports the mutating - * operations concept described in the class documentation (see above). - * @param value a DD instance supplying an extended-precision value. - * @return a self-reference to the DD instance. - */ - public DD setValue(DD value) { - init(value); - return this; - } - - /** - * Set the value for the DD object. This method supports the mutating - * operations concept described in the class documentation (see above). - * @param value a floating point value to be stored in the instance. - * @return a self-reference to the DD instance. - */ - public DD setValue(double value) { - init(value); - return this; - } - - - /** - * Returns a new DoubleDouble whose value is (this + y). - * - * @param y the addend - * @return (this + y) - */ - public final DD add(DD y) - { - return copy(this).selfAdd(y); - } - - /** - * Returns a new DoubleDouble whose value is (this + y). - * - * @param y the addend - * @return (this + y) - */ - public final DD add(double y) - { - return copy(this).selfAdd(y); - } - - /** - * Adds the argument to the value of this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the addend - * @return this object, increased by y - */ - public final DD selfAdd(DD y) - { - return selfAdd(y.hi, y.lo); - } - - /** - * Adds the argument to the value of this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the addend - * @return this object, increased by y - */ - public final DD selfAdd(double y) - { - double H, h, S, s, e, f; - S = hi + y; - e = S - hi; - s = S - e; - s = (y - e) + (hi - s); - f = s + lo; - H = S + f; - h = f + (S - H); - hi = H + h; - lo = h + (H - hi); - return this; - // return selfAdd(y, 0.0); - } - - private final DD selfAdd(double yhi, double ylo) - { - double H, h, T, t, S, s, e, f; - S = hi + yhi; - T = lo + ylo; - e = S - hi; - f = T - lo; - s = S-e; - t = T-f; - s = (yhi-e)+(hi-s); - t = (ylo-f)+(lo-t); - e = s+T; H = S+e; h = e+(S-H); e = t+h; - - double zhi = H + e; - double zlo = e + (H - zhi); - hi = zhi; - lo = zlo; - return this; - } - - /** - * Computes a new DoubleDouble object whose value is (this - y). - * - * @param y the subtrahend - * @return (this - y) - */ - public final DD subtract(DD y) - { - return add(y.negate()); - } - - /** - * Computes a new DoubleDouble object whose value is (this - y). - * - * @param y the subtrahend - * @return (this - y) - */ - public final DD subtract(double y) - { - return add(-y); - } - - - /** - * Subtracts the argument from the value of this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the addend - * @return this object, decreased by y - */ - public final DD selfSubtract(DD y) - { - if (isNaN()) return this; - return selfAdd(-y.hi, -y.lo); - } - - /** - * Subtracts the argument from the value of this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the addend - * @return this object, decreased by y - */ - public final DD selfSubtract(double y) - { - if (isNaN()) return this; - return selfAdd(-y, 0.0); - } - - /** - * Returns a new DoubleDouble whose value is -this. - * - * @return -this - */ - public final DD negate() - { - if (isNaN()) return this; - return new DD(-hi, -lo); - } - - /** - * Returns a new DoubleDouble whose value is (this * y). - * - * @param y the multiplicand - * @return (this * y) - */ - public final DD multiply(DD y) - { - if (y.isNaN()) return createNaN(); - return copy(this).selfMultiply(y); - } - - /** - * Returns a new DoubleDouble whose value is (this * y). - * - * @param y the multiplicand - * @return (this * y) - */ - public final DD multiply(double y) - { - if (Double.isNaN(y)) return createNaN(); - return copy(this).selfMultiply(y, 0.0); - } - - /** - * Multiplies this object by the argument, returning this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the value to multiply by - * @return this object, multiplied by y - */ - public final DD selfMultiply(DD y) - { - return selfMultiply(y.hi, y.lo); - } - - /** - * Multiplies this object by the argument, returning this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the value to multiply by - * @return this object, multiplied by y - */ - public final DD selfMultiply(double y) - { - return selfMultiply(y, 0.0); - } - - private final DD selfMultiply(double yhi, double ylo) - { - double hx, tx, hy, ty, C, c; - C = SPLIT * hi; hx = C-hi; c = SPLIT * yhi; - hx = C-hx; tx = hi-hx; hy = c-yhi; - C = hi*yhi; hy = c-hy; ty = yhi-hy; - c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(hi*ylo+lo*yhi); - double zhi = C+c; hx = C-zhi; - double zlo = c+hx; - hi = zhi; - lo = zlo; - return this; - } - - /** - * Computes a new DoubleDouble whose value is (this / y). - * - * @param y the divisor - * @return a new object with the value (this / y) - */ - public final DD divide(DD y) - { - double hc, tc, hy, ty, C, c, U, u; - C = hi/y.hi; c = SPLIT*C; hc =c-C; u = SPLIT*y.hi; hc = c-hc; - tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; - u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; - c = ((((hi-U)-u)+lo)-C*y.lo)/y.hi; - u = C+c; - - double zhi = u; - double zlo = (C-u)+c; - return new DD(zhi, zlo); - } - - /** - * Computes a new DoubleDouble whose value is (this / y). - * - * @param y the divisor - * @return a new object with the value (this / y) - */ - public final DD divide(double y) - { - if (Double.isNaN(y)) return createNaN(); - return copy(this).selfDivide(y, 0.0); - } - - /** - * Divides this object by the argument, returning this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the value to divide by - * @return this object, divided by y - */ - public final DD selfDivide(DD y) - { - return selfDivide(y.hi, y.lo); - } - - /** - * Divides this object by the argument, returning this. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @param y the value to divide by - * @return this object, divided by y - */ - public final DD selfDivide(double y) - { - return selfDivide(y, 0.0); - } - - private final DD selfDivide(double yhi, double ylo) - { - double hc, tc, hy, ty, C, c, U, u; - C = hi/yhi; c = SPLIT*C; hc =c-C; u = SPLIT*yhi; hc = c-hc; - tc = C-hc; hy = u-yhi; U = C * yhi; hy = u-hy; ty = yhi-hy; - u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; - c = ((((hi-U)-u)+lo)-C*ylo)/yhi; - u = C+c; - - hi = u; - lo = (C-u)+c; - return this; - } - - /** - * Returns a DoubleDouble whose value is 1 / this. - * - * @return the reciprocal of this value - */ - public final DD reciprocal() - { - double hc, tc, hy, ty, C, c, U, u; - C = 1.0/hi; - c = SPLIT*C; - hc =c-C; - u = SPLIT*hi; - hc = c-hc; tc = C-hc; hy = u-hi; U = C*hi; hy = u-hy; ty = hi-hy; - u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; - c = ((((1.0-U)-u))-C*lo)/hi; - - double zhi = C+c; - double zlo = (C-zhi)+c; - return new DD(zhi, zlo); - } - - /** - * Returns the largest (closest to positive infinity) - * value that is not greater than the argument - * and is equal to a mathematical integer. - * Special cases: - *
                      - *
                    • If this value is NaN, returns NaN. - *
                    - * - * @return the largest (closest to positive infinity) - * value that is not greater than the argument - * and is equal to a mathematical integer. - */ - public DD floor() - { - if (isNaN()) return NaN; - double fhi=Math.floor(hi); - double flo = 0.0; - // Hi is already integral. Floor the low word - if (fhi == hi) { - flo = Math.floor(lo); - } - // do we need to renormalize here? - return new DD(fhi, flo); - } - - /** - * Returns the smallest (closest to negative infinity) value - * that is not less than the argument and is equal to a mathematical integer. - * Special cases: - *
                      - *
                    • If this value is NaN, returns NaN. - *
                    - * - * @return the smallest (closest to negative infinity) value - * that is not less than the argument and is equal to a mathematical integer. - */ - public DD ceil() - { - if (isNaN()) return NaN; - double fhi=Math.ceil(hi); - double flo = 0.0; - // Hi is already integral. Ceil the low word - if (fhi == hi) { - flo = Math.ceil(lo); - // do we need to renormalize here? - } - return new DD(fhi, flo); - } - - /** - * Returns an integer indicating the sign of this value. - *
                      - *
                    • if this value is > 0, returns 1 - *
                    • if this value is < 0, returns -1 - *
                    • if this value is = 0, returns 0 - *
                    • if this value is NaN, returns 0 - *
                    - * - * @return an integer indicating the sign of this value - */ - public int signum() - { - if (hi > 0) return 1; - if (hi < 0) return -1; - if (lo > 0) return 1; - if (lo < 0) return -1; - return 0; - } - - /** - * Rounds this value to the nearest integer. - * The value is rounded to an integer by adding 1/2 and taking the floor of the result. - * Special cases: - *
                      - *
                    • If this value is NaN, returns NaN. - *
                    - * - * @return this value rounded to the nearest integer - */ - public DD rint() - { - if (isNaN()) return this; - // may not be 100% correct - DD plus5 = this.add(0.5); - return plus5.floor(); - } - - /** - * Returns the integer which is largest in absolute value and not further - * from zero than this value. - * Special cases: - *
                      - *
                    • If this value is NaN, returns NaN. - *
                    - * - * @return the integer which is largest in absolute value and not further from zero than this value - */ - public DD trunc() - { - if (isNaN()) return NaN; - if (isPositive()) - return floor(); - else - return ceil(); - } - - /** - * Returns the absolute value of this value. - * Special cases: - *
                      - *
                    • If this value is NaN, it is returned. - *
                    - * - * @return the absolute value of this value - */ - public DD abs() - { - if (isNaN()) return NaN; - if (isNegative()) - return negate(); - return new DD(this); - } - - /** - * Computes the square of this value. - * - * @return the square of this value. - */ - public DD sqr() - { - return this.multiply(this); - } - - /** - * Squares this object. - * To prevent altering constants, - * this method must only be used on values known to - * be newly created. - * - * @return the square of this value. - */ - public DD selfSqr() - { - return this.selfMultiply(this); - } - - /** - * Computes the square of this value. - * - * @return the square of this value. - */ - public static DD sqr(double x) - { - return valueOf(x).selfMultiply(x); - } - - /** - * Computes the positive square root of this value. - * If the number is NaN or negative, NaN is returned. - * - * @return the positive square root of this number. - * If the argument is NaN or less than zero, the result is NaN. - */ - public DD sqrt() - { - /* Strategy: Use Karp's trick: if x is an approximation - to sqrt(a), then - - sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx) - - The approximation is accurate to twice the accuracy of x. - Also, the multiplication (a*x) and [-]*x can be done with - only half the precision. - */ - - if (isZero()) - return valueOf(0.0); - - if (isNegative()) { - return NaN; - } - - double x = 1.0 / Math.sqrt(hi); - double ax = hi * x; - - DD axdd = valueOf(ax); - DD diffSq = this.subtract(axdd.sqr()); - double d2 = diffSq.hi * (x * 0.5); - - return axdd.add(d2); - } - - public static DD sqrt(double x) - { - return valueOf(x).sqrt(); - } - - /** - * Computes the value of this number raised to an integral power. - * Follows semantics of Java Math.pow as closely as possible. - * - * @param exp the integer exponent - * @return x raised to the integral power exp - */ - public DD pow(int exp) - { - if (exp == 0.0) - return valueOf(1.0); - - DD r = new DD(this); - DD s = valueOf(1.0); - int n = Math.abs(exp); - - if (n > 1) { - /* Use binary exponentiation */ - while (n > 0) { - if (n % 2 == 1) { - s.selfMultiply(r); - } - n /= 2; - if (n > 0) - r = r.sqr(); - } - } else { - s = r; - } - - /* Compute the reciprocal if n is negative. */ - if (exp < 0) - return s.reciprocal(); - return s; - } - - - /*------------------------------------------------------------ - * Ordering Functions - *------------------------------------------------------------ - */ - - /** - * Computes the minimum of this and another DD number. - * - * @param x a DD number - * @return the minimum of the two numbers - */ - public DD min(DD x) { - if (this.le(x)) { - return this; - } - else { - return x; - } - } - - /** - * Computes the maximum of this and another DD number. - * - * @param x a DD number - * @return the maximum of the two numbers - */ - public DD max(DD x) { - if (this.ge(x)) { - return this; - } - else { - return x; - } - } - - /*------------------------------------------------------------ - * Conversion Functions - *------------------------------------------------------------ - */ - - /** - * Converts this value to the nearest double-precision number. - * - * @return the nearest double-precision number to this value - */ - public double doubleValue() - { - return hi + lo; - } - - /** - * Converts this value to the nearest integer. - * - * @return the nearest integer to this value - */ - public int intValue() - { - return (int) hi; - } - - /*------------------------------------------------------------ - * Predicates - *------------------------------------------------------------ - */ - - /** - * Tests whether this value is equal to 0. - * - * @return true if this value is equal to 0 - */ - public boolean isZero() - { - return hi == 0.0 && lo == 0.0; - } - - /** - * Tests whether this value is less than 0. - * - * @return true if this value is less than 0 - */ - public boolean isNegative() - { - return hi < 0.0 || (hi == 0.0 && lo < 0.0); - } - - /** - * Tests whether this value is greater than 0. - * - * @return true if this value is greater than 0 - */ - public boolean isPositive() - { - return hi > 0.0 || (hi == 0.0 && lo > 0.0); - } - - /** - * Tests whether this value is NaN. - * - * @return true if this value is NaN - */ - public boolean isNaN() { return Double.isNaN(hi); } - - /** - * Tests whether this value is equal to another DoubleDouble value. - * - * @param y a DoubleDouble value - * @return true if this value = y - */ - public boolean equals(DD y) - { - return hi == y.hi && lo == y.lo; - } - - /** - * Tests whether this value is greater than another DoubleDouble value. - * @param y a DoubleDouble value - * @return true if this value > y - */ - public boolean gt(DD y) - { - return (hi > y.hi) || (hi == y.hi && lo > y.lo); - } - /** - * Tests whether this value is greater than or equals to another DoubleDouble value. - * @param y a DoubleDouble value - * @return true if this value >= y - */ - public boolean ge(DD y) - { - return (hi > y.hi) || (hi == y.hi && lo >= y.lo); - } - /** - * Tests whether this value is less than another DoubleDouble value. - * @param y a DoubleDouble value - * @return true if this value < y - */ - public boolean lt(DD y) - { - return (hi < y.hi) || (hi == y.hi && lo < y.lo); - } - /** - * Tests whether this value is less than or equal to another DoubleDouble value. - * @param y a DoubleDouble value - * @return true if this value <= y - */ - public boolean le(DD y) - { - return (hi < y.hi) || (hi == y.hi && lo <= y.lo); - } - - /** - * Compares two DoubleDouble objects numerically. - * - * @return -1,0 or 1 depending on whether this value is less than, equal to - * or greater than the value of o - */ - public int compareTo(Object o) - { - DD other = (DD) o; - - if (hi < other.hi) return -1; - if (hi > other.hi) return 1; - if (lo < other.lo) return -1; - if (lo > other.lo) return 1; - return 0; - } - - - /*------------------------------------------------------------ - * Output - *------------------------------------------------------------ - */ - - private static final int MAX_PRINT_DIGITS = 32; - private static final DD TEN = DD.valueOf(10.0); - private static final DD ONE = DD.valueOf(1.0); - private static final String SCI_NOT_EXPONENT_CHAR = "E"; - private static final String SCI_NOT_ZERO = "0.0E0"; - - /** - * Dumps the components of this number to a string. - * - * @return a string showing the components of the number - */ - public String dump() - { - return "DD<" + hi + ", " + lo + ">"; - } - - /** - * Returns a string representation of this number, in either standard or scientific notation. - * If the magnitude of the number is in the range [ 10-3, 108 ] - * standard notation will be used. Otherwise, scientific notation will be used. - * - * @return a string representation of this number - */ - public String toString() - { - int mag = magnitude(hi); - if (mag >= -3 && mag <= 20) - return toStandardNotation(); - return toSciNotation(); - } - - /** - * Returns the string representation of this value in standard notation. - * - * @return the string representation in standard notation - */ - public String toStandardNotation() - { - String specialStr = getSpecialNumberString(); - if (specialStr != null) - return specialStr; - - int[] magnitude = new int[1]; - String sigDigits = extractSignificantDigits(true, magnitude); - int decimalPointPos = magnitude[0] + 1; - - String num = sigDigits; - // add a leading 0 if the decimal point is the first char - if (sigDigits.charAt(0) == '.') { - num = "0" + sigDigits; - } - else if (decimalPointPos < 0) { - num = "0." + stringOfChar('0', -decimalPointPos) + sigDigits; - } - else if (sigDigits.indexOf('.') == -1) { - // no point inserted - sig digits must be smaller than magnitude of number - // add zeroes to end to make number the correct size - int numZeroes = decimalPointPos - sigDigits.length(); - String zeroes = stringOfChar('0', numZeroes); - num = sigDigits + zeroes + ".0"; - } - - if (this.isNegative()) - return "-" + num; - return num; - } - - /** - * Returns the string representation of this value in scientific notation. - * - * @return the string representation in scientific notation - */ - public String toSciNotation() - { - // special case zero, to allow as - if (isZero()) - return SCI_NOT_ZERO; - - String specialStr = getSpecialNumberString(); - if (specialStr != null) - return specialStr; - - int[] magnitude = new int[1]; - String digits = extractSignificantDigits(false, magnitude); - String expStr = SCI_NOT_EXPONENT_CHAR + magnitude[0]; - - // should never have leading zeroes - // MD - is this correct? Or should we simply strip them if they are present? - if (digits.charAt(0) == '0') { - throw new IllegalStateException("Found leading zero: " + digits); - } - - // add decimal point - String trailingDigits = ""; - if (digits.length() > 1) - trailingDigits = digits.substring(1); - String digitsWithDecimal = digits.charAt(0) + "." + trailingDigits; - - if (this.isNegative()) - return "-" + digitsWithDecimal + expStr; - return digitsWithDecimal + expStr; - } - - - /** - * Extracts the significant digits in the decimal representation of the argument. - * A decimal point may be optionally inserted in the string of digits - * (as long as its position lies within the extracted digits - * - if not, the caller must prepend or append the appropriate zeroes and decimal point). - * - * @param y the number to extract ( >= 0) - * @param decimalPointPos the position in which to insert a decimal point - * @return the string containing the significant digits and possibly a decimal point - */ - private String extractSignificantDigits(boolean insertDecimalPoint, int[] magnitude) - { - DD y = this.abs(); - // compute *correct* magnitude of y - int mag = magnitude(y.hi); - DD scale = TEN.pow(mag); - y = y.divide(scale); - - // fix magnitude if off by one - if (y.gt(TEN)) { - y = y.divide(TEN); - mag += 1; - } - else if (y.lt(ONE)) { - y = y.multiply(TEN); - mag -= 1; - } - - int decimalPointPos = mag + 1; - StringBuffer buf = new StringBuffer(); - int numDigits = MAX_PRINT_DIGITS - 1; - for (int i = 0; i <= numDigits; i++) { - if (insertDecimalPoint && i == decimalPointPos) { - buf.append('.'); - } - int digit = (int) y.hi; -// System.out.println("printDump: [" + i + "] digit: " + digit + " y: " + y.dump() + " buf: " + buf); - - /** - * This should never happen, due to heuristic checks on remainder below - */ - if (digit < 0 || digit > 9) { -// System.out.println("digit > 10 : " + digit); -// throw new IllegalStateException("Internal errror: found digit = " + digit); - } - /** - * If a negative remainder is encountered, simply terminate the extraction. - * This is robust, but maybe slightly inaccurate. - * My current hypothesis is that negative remainders only occur for very small lo components, - * so the inaccuracy is tolerable - */ - if (digit < 0) { - break; - // throw new IllegalStateException("Internal errror: found digit = " + digit); - } - boolean rebiasBy10 = false; - char digitChar = 0; - if (digit > 9) { - // set flag to re-bias after next 10-shift - rebiasBy10 = true; - // output digit will end up being '9' - digitChar = '9'; - } - else { - digitChar = (char) ('0' + digit); - } - buf.append(digitChar); - y = (y.subtract(DD.valueOf(digit)) - .multiply(TEN)); - if (rebiasBy10) - y.selfAdd(TEN); - - boolean continueExtractingDigits = true; - /** - * Heuristic check: if the remaining portion of - * y is non-positive, assume that output is complete - */ -// if (y.hi <= 0.0) -// if (y.hi < 0.0) -// continueExtractingDigits = false; - /** - * Check if remaining digits will be 0, and if so don't output them. - * Do this by comparing the magnitude of the remainder with the expected precision. - */ - int remMag = magnitude(y.hi); - if (remMag < 0 && Math.abs(remMag) >= (numDigits - i)) - continueExtractingDigits = false; - if (! continueExtractingDigits) - break; - } - magnitude[0] = mag; - return buf.toString(); - } - - - /** - * Creates a string of a given length containing the given character - * - * @param ch the character to be repeated - * @param len the len of the desired string - * @return the string - */ - private static String stringOfChar(char ch, int len) - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < len; i++) { - buf.append(ch); - } - return buf.toString(); - } - - /** - * Returns the string for this value if it has a known representation. - * (E.g. NaN or 0.0) - * - * @return the string for this special number - * or null if the number is not a special number - */ - private String getSpecialNumberString() - { - if (isZero()) return "0.0"; - if (isNaN()) return "NaN "; - return null; - } - - - - /** - * Determines the decimal magnitude of a number. - * The magnitude is the exponent of the greatest power of 10 which is less than - * or equal to the number. - * - * @param x the number to find the magnitude of - * @return the decimal magnitude of x - */ - private static int magnitude(double x) - { - double xAbs = Math.abs(x); - double xLog10 = Math.log(xAbs) / Math.log(10); - int xMag = (int) Math.floor(xLog10); - /** - * Since log computation is inexact, there may be an off-by-one error - * in the computed magnitude. - * Following tests that magnitude is correct, and adjusts it if not - */ - double xApprox = Math.pow(10, xMag); - if (xApprox * 10 <= xAbs) - xMag += 1; - - return xMag; - } - - - /*------------------------------------------------------------ - * Input - *------------------------------------------------------------ - */ - - /** - * Converts a string representation of a real number into a DoubleDouble value. - * The format accepted is similar to the standard Java real number syntax. - * It is defined by the following regular expression: - *
                    -   * [+|-] {digit} [ . {digit} ] [ ( e | E ) [+|-] {digit}+
                    -   * 
                    -   * 
                    -   * @param str the string to parse
                    -   * @return the value of the parsed number
                    -   * @throws NumberFormatException if str is not a valid representation of a number
                    -   */
                    -  public static DD parse(String str)
                    -    throws NumberFormatException
                    -  {
                    -    int i = 0;
                    -    int strlen = str.length();
                    -    
                    -    // skip leading whitespace
                    -    while (Character.isWhitespace(str.charAt(i)))
                    -      i++;
                    -    
                    -    // check for sign
                    -    boolean isNegative = false;
                    -    if (i < strlen) {
                    -      char signCh = str.charAt(i);
                    -      if (signCh == '-' || signCh == '+') {
                    -        i++;
                    -        if (signCh == '-') isNegative = true;
                    -      }
                    -    }
                    -    
                    -    // scan all digits and accumulate into an integral value
                    -    // Keep track of the location of the decimal point (if any) to allow scaling later
                    -    DD val = new DD();
                    -
                    -    int numDigits = 0;
                    -    int numBeforeDec = 0;
                    -    int exp = 0;
                    -    while (true) {
                    -      if (i >= strlen)
                    -        break;
                    -      char ch = str.charAt(i);
                    -      i++;
                    -      if (Character.isDigit(ch)) {
                    -        double d = ch - '0';
                    -        val.selfMultiply(TEN);
                    -        // MD: need to optimize this
                    -        val.selfAdd(d);
                    -        numDigits++;
                    -        continue;
                    -      }
                    -      if (ch == '.') {
                    -        numBeforeDec = numDigits;
                    -        continue;
                    -      }
                    -      if (ch == 'e' || ch == 'E') {
                    -        String expStr = str.substring(i);
                    -        // this should catch any format problems with the exponent
                    -        try {
                    -          exp = Integer.parseInt(expStr);
                    -        }
                    -        catch (NumberFormatException ex) {
                    -          throw new NumberFormatException("Invalid exponent " + expStr + " in string " + str);  
                    -        }
                    -        break;
                    -      }
                    -      throw new NumberFormatException("Unexpected character '" + ch 
                    -          + "' at position " + i 
                    -          + " in string " + str);
                    -    }
                    -    DD val2 = val;
                    -    
                    -    // scale the number correctly
                    -    int numDecPlaces = numDigits - numBeforeDec - exp;
                    -    if (numDecPlaces == 0) {
                    -      val2 = val;
                    -    }
                    -    else if (numDecPlaces > 0) {  
                    -      DD scale = TEN.pow(numDecPlaces);
                    -      val2 = val.divide(scale);
                    -    }
                    -    else if (numDecPlaces < 0) {
                    -      DD scale = TEN.pow(-numDecPlaces);    
                    -      val2 = val.multiply(scale);
                    -    }
                    -    // apply leading sign, if any
                    -    if (isNegative) {
                    -      return val2.negate();
                    -    }
                    -    return val2;
                    -
                    -  }
                    -}
                    \ No newline at end of file
                    diff --git a/src/main/java/com/vividsolutions/jts/math/MathUtil.java b/src/main/java/com/vividsolutions/jts/math/MathUtil.java
                    deleted file mode 100644
                    index d0587bd75c..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/math/MathUtil.java
                    +++ /dev/null
                    @@ -1,146 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.math;
                    -
                    -/**
                    - * Various utility functions for mathematical and numerical operations.
                    - * 
                    - * @author mbdavis
                    - *
                    - */
                    -public class MathUtil 
                    -{
                    -  /**
                    -   * Clamps a double value to a given range.
                    -   * @param x the value to clamp
                    -   * @param min the minimum value of the range
                    -   * @param max the maximum value of the range
                    -   * @return the clamped value
                    -   */
                    -  public static double clamp(double x, double min, double max)
                    -  {
                    -    if (x < min) return min;
                    -    if (x > max) return max;
                    -    return x;
                    -  }
                    -  
                    -  /**
                    -   * Clamps an int value to a given range.
                    -   * @param x the value to clamp
                    -   * @param min the minimum value of the range
                    -   * @param max the maximum value of the range
                    -   * @return the clamped value
                    -   */
                    -  public static int clamp(int x, int min, int max)
                    -  {
                    -    if (x < min) return min;
                    -    if (x > max) return max;
                    -    return x;
                    -  }
                    -  
                    -  private static final double LOG_10 = Math.log(10);
                    -  
                    -  /**
                    -   * Computes the base-10 logarithm of a double value.
                    -   * 
                      - *
                    • If the argument is NaN or less than zero, then the result is NaN. - *
                    • If the argument is positive infinity, then the result is positive infinity. - *
                    • If the argument is positive zero or negative zero, then the result is negative infinity. - *
                    - * - * @param x a positive number - * @return the value log a, the base-10 logarithm of the input value - */ - public static double log10(double x) - { - double ln = Math.log(x); - if (Double.isInfinite(ln)) return ln; - if (Double.isNaN(ln)) return ln; - return ln / LOG_10; - } - - /** - * Computes an index which wraps around a given maximum value. - * For values >= 0, this is equals to val % max. - * For values < 0, this is equal to max - (-val) % max - * - * @param index the value to wrap - * @param max the maximum value (or modulus) - * @return the wrapped index - */ - public static int wrap(int index, int max) - { - if (index < 0) { - return max - ((-index) % max); - } - return index % max; - } - - /** - * Computes the average of two numbers. - * - * @param x1 a number - * @param x2 a number - * @return the average of the inputs - */ - public static double average(double x1, double x2) - { - return (x1 + x2) / 2.0; - } - - public static double max(double v1, double v2, double v3) - { - double max = v1; - if (v2 > max) max = v2; - if (v3 > max) max = v3; - return max; - } - - public static double max(double v1, double v2, double v3, double v4) - { - double max = v1; - if (v2 > max) max = v2; - if (v3 > max) max = v3; - if (v4 > max) max = v4; - return max; - } - - public static double min(double v1, double v2, double v3, double v4) - { - double min = v1; - if (v2 < min) min = v2; - if (v3 < min) min = v3; - if (v4 < min) min = v4; - return min; - } -} diff --git a/src/main/java/com/vividsolutions/jts/math/Matrix.java b/src/main/java/com/vividsolutions/jts/math/Matrix.java deleted file mode 100644 index 741351a0f9..0000000000 --- a/src/main/java/com/vividsolutions/jts/math/Matrix.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.math; - -/** - * Implements some 2D matrix operations - * (in particular, solving systems of linear equations). - * - * @author Martin Davis - * - */ -public class Matrix -{ - private static void swapRows(double[][] m, int i, int j) - { - if (i == j) return; - for (int col = 0; col < m[0].length; col++) { - double temp = m[i][col]; - m[i][col] = m[j][col]; - m[j][col] = temp; - } - } - - private static void swapRows(double[] m, int i, int j) - { - if (i == j) return; - double temp = m[i]; - m[i] = m[j]; - m[j] = temp; - } - - /** - * Solves a system of equations using Gaussian Elimination. - * In order to avoid overhead the algorithm runs in-place - * on A - if A should not be modified the client must supply a copy. - * - * @param a an nxn matrix in row/column order )modified by this method) - * @param b a vector of length n - * - * @return a vector containing the solution (if any) - * or null if the system has no or no unique solution - * - * @throws IllegalArgumentException if the matrix is the wrong size - */ - public static double[] solve( double[][] a, double[] b ) - { - int n = b.length; - if ( a.length != n || a[0].length != n ) - throw new IllegalArgumentException("Matrix A is incorrectly sized"); - - // Use Gaussian Elimination with partial pivoting. - // Iterate over each row - for (int i = 0; i < n; i++ ) { - // Find the largest pivot in the rows below the current one. - int maxElementRow = i; - for (int j = i + 1; j < n; j++ ) - if ( Math.abs( a[j][i] ) > Math.abs( a[maxElementRow][i] ) ) - maxElementRow = j; - - if ( a[maxElementRow][i] == 0.0 ) - return null; - - // Exchange current row and maxElementRow in A and b. - swapRows(a, i, maxElementRow ); - swapRows(b, i, maxElementRow ); - - // Eliminate using row i - for (int j = i + 1; j < n; j++ ) { - double rowFactor = a[j][i] / a[i][i]; - for (int k = n - 1; k >= i; k-- ) - a[j][k] -= a[i][k] * rowFactor; - b[j] -= b[i] * rowFactor; - } - } - - /** - * A is now (virtually) in upper-triangular form. - * The solution vector is determined by back-substitution. - */ - double[] solution = new double[n]; - for (int j = n - 1; j >= 0; j-- ) { - double t = 0.0; - for (int k = j + 1; k < n; k++ ) - t += a[j][k] * solution[k]; - solution[j] = ( b[j] - t ) / a[j][j]; - } - return solution; - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/math/Plane3D.java b/src/main/java/com/vividsolutions/jts/math/Plane3D.java deleted file mode 100644 index e28fcbf208..0000000000 --- a/src/main/java/com/vividsolutions/jts/math/Plane3D.java +++ /dev/null @@ -1,112 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.math; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Models a plane in 3-dimensional Cartesian space. - * - * @author mdavis - * - */ -public class Plane3D { - - /** - * Enums for the 3 coordinate planes - */ - public static final int XY_PLANE = 1; - public static final int YZ_PLANE = 2; - public static final int XZ_PLANE = 3; - - private Vector3D normal; - private Coordinate basePt; - - public Plane3D(Vector3D normal, Coordinate basePt) - { - this.normal = normal; - this.basePt = basePt; - } - - /** - * Computes the oriented distance from a point to the plane. - * The distance is: - *
                      - *
                    • positive if the point lies above the plane (relative to the plane normal) - *
                    • zero if the point is on the plane - *
                    • negative if the point lies below the plane (relative to the plane normal) - *
                    - * - * @param p the point to compute the distance for - * @return the oriented distance to the plane - */ - public double orientedDistance(Coordinate p) { - Vector3D pb = new Vector3D(p, basePt); - double pbdDotNormal = pb.dot(normal); - if (Double.isNaN(pbdDotNormal)) - throw new IllegalArgumentException("3D Coordinate has NaN ordinate"); - double d = pbdDotNormal / normal.length(); - return d; - } - - /** - * Computes the axis plane that this plane lies closest to. - *

                    - * Geometries lying in this plane undergo least distortion - * (and have maximum area) - * when projected to the closest axis plane. - * This provides optimal conditioning for - * computing a Point-in-Polygon test. - * - * @return the index of the closest axis plane. - */ - public int closestAxisPlane() { - double xmag = Math.abs(normal.getX()); - double ymag = Math.abs(normal.getY()); - double zmag = Math.abs(normal.getZ()); - if (xmag > ymag) { - if (xmag > zmag) - return YZ_PLANE; - else - return XY_PLANE; - } - // y >= x - else if (zmag > ymag) { - return XY_PLANE; - } - // y >= z - return XZ_PLANE; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/math/Vector2D.java b/src/main/java/com/vividsolutions/jts/math/Vector2D.java deleted file mode 100644 index 4541e27b43..0000000000 --- a/src/main/java/com/vividsolutions/jts/math/Vector2D.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.math; - -import com.vividsolutions.jts.algorithm.Angle; -import com.vividsolutions.jts.algorithm.RobustDeterminant; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.util.Assert; - -/** - * A 2-dimensional mathematical vector represented by double-precision X and Y components. - * - * @author mbdavis - * - */ -public class Vector2D { - /** - * Creates a new vector with given X and Y components. - * - * @param x the x component - * @param y the y component - * @return a new vector - */ - public static Vector2D create(double x, double y) { - return new Vector2D(x, y); - } - - /** - * Creates a new vector from an existing one. - * - * @param v the vector to copy - * @return a new vector - */ - public static Vector2D create(Vector2D v) { - return new Vector2D(v); - } - - /** - * Creates a vector from a {@link Coordinate}. - * - * @param coord the Coordinate to copy - * @return a new vector - */ - public static Vector2D create(Coordinate coord) { - return new Vector2D(coord); - } - - /** - * Creates a vector with the direction and magnitude - * of the difference between the - * to and from {@link Coordinate}s. - * - * @param from the origin Coordinate - * @param to the destination Coordinate - * @return a new vector - */ - public static Vector2D create(Coordinate from, Coordinate to) { - return new Vector2D(from, to); - } - - /** - * The X component of this vector. - */ - private double x; - - /** - * The Y component of this vector. - */ - private double y; - - public Vector2D() { - this(0.0, 0.0); - } - - public Vector2D(double x, double y) { - this.x = x; - this.y = y; - } - - public Vector2D(Vector2D v) { - x = v.x; - y = v.y; - } - - public Vector2D(Coordinate from, Coordinate to) { - x = to.x - from.x; - y = to.y - from.y; - } - - public Vector2D(Coordinate v) { - x = v.x; - y = v.y; - } - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public double getComponent(int index) { - if (index == 0) - return x; - return y; - } - - public Vector2D add(Vector2D v) { - return create(x + v.x, y + v.y); - } - - public Vector2D subtract(Vector2D v) { - return create(x - v.x, y - v.y); - } - - /** - * Multiplies the vector by a scalar value. - * - * @param d the value to multiply by - * @return a new vector with the value v * d - */ - public Vector2D multiply(double d) { - return create(x * d, y * d); - } - - /** - * Divides the vector by a scalar value. - * - * @param d the value to divide by - * @return a new vector with the value v / d - */ - public Vector2D divide(double d) { - return create(x / d, y / d); - } - - public Vector2D negate() { - return create(-x , -y); - } - - public double length() { - return Math.sqrt(x * x + y * y); - } - - public double lengthSquared() { - return x * x + y * y; - } - - public Vector2D normalize() { - double length = length(); - if (length > 0.0) - return divide(length); - return create(0.0, 0.0); - } - - public Vector2D average(Vector2D v) { - return weightedSum(v, 0.5); - } - - /** - * Computes the weighted sum of this vector - * with another vector, - * with this vector contributing a fraction - * of frac to the total. - *

                    - * In other words, - *

                    -	 * sum = frac * this + (1 - frac) * v
                    -	 * 
                    - * - * @param v the vector to sum - * @param frac the fraction of the total contributed by this vector - * @return the weighted sum of the two vectors - */ - public Vector2D weightedSum(Vector2D v, double frac) { - return create( - frac * x + (1.0 - frac) * v.x, - frac * y + (1.0 - frac) * v.y); - } - - /** - * Computes the distance between this vector and another one. - * @param v a vector - * @return the distance between the vectors - */ - public double distance(Vector2D v) - { - double delx = v.x - x; - double dely = v.y - y; - return Math.sqrt(delx * delx + dely * dely); - } - - /** - * Computes the dot-product of two vectors - * - * @param v a vector - * @return the dot product of the vectors - */ - public double dot(Vector2D v) { - return x * v.x + y * v.y; - } - - public double angle() - { - return Math.atan2(y, x); - } - - public double angle(Vector2D v) - { - return Angle.diff(v.angle(), angle()); - } - - public double angleTo(Vector2D v) - { - double a1 = angle(); - double a2 = v.angle(); - double angDel = a2 - a1; - - // normalize, maintaining orientation - if (angDel <= -Math.PI) - return angDel + Angle.PI_TIMES_2; - if (angDel > Math.PI) - return angDel - Angle.PI_TIMES_2; - return angDel; - } - - public Vector2D rotate(double angle) - { - double cos = Math.cos(angle); - double sin = Math.sin(angle); - return create( - x * cos - y * sin, - x * sin + y * cos - ); - } - - /** - * Rotates a vector by a given number of quarter-circles (i.e. multiples of 90 - * degrees or Pi/2 radians). A positive number rotates counter-clockwise, a - * negative number rotates clockwise. Under this operation the magnitude of - * the vector and the absolute values of the ordinates do not change, only - * their sign and ordinate index. - * - * @param numQuarters - * the number of quarter-circles to rotate by - * @return the rotated vector. - */ - public Vector2D rotateByQuarterCircle(int numQuarters) { - int nQuad = numQuarters % 4; - if (numQuarters < 0 && nQuad != 0) { - nQuad = nQuad + 4; - } - switch (nQuad) { - case 0: - return create(x, y); - case 1: - return create(-y, x); - case 2: - return create(-x, -y); - case 3: - return create(y, -x); - } - Assert.shouldNeverReachHere(); - return null; - } - - public boolean isParallel(Vector2D v) - { - return 0.0 == RobustDeterminant.signOfDet2x2(x, y, v.x, v.y); - } - - public Coordinate translate(Coordinate coord) { - return new Coordinate(x + coord.x, y + coord.y); - } - - public Coordinate toCoordinate() { - return new Coordinate(x, y); - } - - /** - * Creates a copy of this vector - * - * @return a copy of this vector - */ - public Object clone() - { - return new Vector2D(this); - } - - /** - * Gets a string representation of this vector - * - * @return a string representing this vector - */ - public String toString() { - return "[" + x + ", " + y + "]"; - } - - /** - * Tests if a vector o has the same values for the x and y - * components. - * - * @param o - * a Vector2D with which to do the comparison. - * @return true if other is a Vector2D with the same - * values for the x and y components. - */ - public boolean equals(Object o) { - if (!(o instanceof Vector2D)) { - return false; - } - Vector2D v = (Vector2D) o; - return x == v.x && y == v.y; - } - - /** - * Gets a hashcode for this vector. - * - * @return a hashcode for this vector - */ - public int hashCode() { - // Algorithm from Effective Java by Joshua Bloch - int result = 17; - result = 37 * result + Coordinate.hashCode(x); - result = 37 * result + Coordinate.hashCode(y); - return result; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/math/Vector3D.java b/src/main/java/com/vividsolutions/jts/math/Vector3D.java deleted file mode 100644 index f9efdb1e14..0000000000 --- a/src/main/java/com/vividsolutions/jts/math/Vector3D.java +++ /dev/null @@ -1,182 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.math; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Represents a vector in 3-dimensional Cartesian space. - * - * @author mdavis - * - */ -public class Vector3D { - - /** - * Computes the dot product of the 3D vectors AB and CD. - * - * @param A - * @param B - * @param C - * @param D - * @return the dot product - */ - public static double dot(Coordinate A, Coordinate B, Coordinate C, Coordinate D) - { - double ABx = B.x - A.x; - double ABy = B.y - A.y; - double ABz = B.z - A.z; - double CDx = D.x - C.x; - double CDy = D.y - C.y; - double CDz = D.z - C.z; - return ABx*CDx + ABy*CDy + ABz*CDz; - } - - /** - * Creates a new vector with given X and Y components. - * - * @param x - * the x component - * @param y - * the y component - * @param z - * the z component - * @return a new vector - */ - public static Vector3D create(double x, double y, double z) { - return new Vector3D(x, y, z); - } - - /** - * Creates a vector from a {@link Coordinate}. - * - * @param coord - * the Coordinate to copy - * @return a new vector - */ - public static Vector3D create(Coordinate coord) { - return new Vector3D(coord); - } - - public Vector3D(Coordinate v) { - x = v.x; - y = v.y; - z = v.z; - } - - /** - * Computes the 3D dot-product of two {@link Coordinate}s. - * - * @param v1 the first vector - * @param v2 the second vector - * @return the dot product of the vectors - */ - public static double dot(Coordinate v1, Coordinate v2) { - return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; - } - - private double x; - private double y; - private double z; - - public Vector3D(Coordinate from, Coordinate to) { - x = to.x - from.x; - y = to.y - from.y; - z = to.z - from.z; - } - - public Vector3D(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public double getZ() { - return z; - } - - - /** - * Computes the dot-product of two vectors - * - * @param v - * a vector - * @return the dot product of the vectors - */ - public double dot(Vector3D v) { - return x * v.x + y * v.y + z * v.z; - } - - public double length() { - return Math.sqrt(x * x + y * y + z * z); - } - - public static double length(Coordinate v) { - return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - } - - public Vector3D normalize() { - double length = length(); - if (length > 0.0) - return divide(length()); - return create(0.0, 0.0, 0.0); - } - - private Vector3D divide(double d) { - return create(x / d, y / d, z / d); - } - - public static Coordinate normalize(Coordinate v) { - double len = length(v); - return new Coordinate(v.x / len, v.y / len, v.z / len); - } - /** - * Gets a string representation of this vector - * - * @return a string representing this vector - */ - public String toString() { - return "[" + x + ", " + y + ", " + z + "]"; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/BasicSegmentString.java b/src/main/java/com/vividsolutions/jts/noding/BasicSegmentString.java deleted file mode 100644 index 66f94ff9ee..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/BasicSegmentString.java +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * Represents a list of contiguous line segments, - * and supports noding the segments. - * The line segments are represented by an array of {@link Coordinate}s. - * Intended to optimize the noding of contiguous segments by - * reducing the number of allocated objects. - * SegmentStrings can carry a context object, which is useful - * for preserving topological or parentage information. - * All noded substrings are initialized with the same context object. - * - * @version 1.7 - */ -public class BasicSegmentString - implements SegmentString -{ - private Coordinate[] pts; - private Object data; - - /** - * Creates a new segment string from a list of vertices. - * - * @param pts the vertices of the segment string - * @param data the user-defined data of this segment string (may be null) - */ - public BasicSegmentString(Coordinate[] pts, Object data) - { - this.pts = pts; - this.data = data; - } - - /** - * Gets the user-defined data for this segment string. - * - * @return the user-defined data - */ - public Object getData() { return data; } - - /** - * Sets the user-defined data for this segment string. - * - * @param data an Object containing user-defined data - */ - public void setData(Object data) { this.data = data; } - - public int size() { return pts.length; } - public Coordinate getCoordinate(int i) { return pts[i]; } - public Coordinate[] getCoordinates() { return pts; } - - public boolean isClosed() - { - return pts[0].equals(pts[pts.length - 1]); - } - - /** - * Gets the octant of the segment starting at vertex index. - * - * @param index the index of the vertex starting the segment. Must not be - * the last index in the vertex list - * @return the octant of the segment at the vertex - */ - public int getSegmentOctant(int index) - { - if (index == pts.length - 1) return -1; - return Octant.octant(getCoordinate(index), getCoordinate(index + 1)); - } - - public String toString() - { - return WKTWriter.toLineString(new CoordinateArraySequence(pts)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/FastNodingValidator.java b/src/main/java/com/vividsolutions/jts/noding/FastNodingValidator.java deleted file mode 100644 index c1beffc0ba..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/FastNodingValidator.java +++ /dev/null @@ -1,174 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.io.*; - -/** - * Validates that a collection of {@link SegmentString}s is correctly noded. - * Indexing is used to improve performance. - * In the most common use case, validation stops after a single - * non-noded intersection is detected, - * but the class can be requested to detect all intersections - * by using the {@link #setFindAllIntersections(boolean)} method. - *

                    - * The validator does not check for a-b-a topology collapse situations. - *

                    - * The validator does not check for endpoint-interior vertex intersections. - * This should not be a problem, since the JTS noders should be - * able to compute intersections between vertices correctly. - *

                    - * The client may either test the {@link #isValid()} condition, - * or request that a suitable {@link TopologyException} be thrown. - * - * @version 1.7 - */ -public class FastNodingValidator -{ - public static List computeIntersections(Collection segStrings) - { - FastNodingValidator nv = new FastNodingValidator(segStrings); - nv.setFindAllIntersections(true); - nv.isValid(); - return nv.getIntersections(); - } - - private LineIntersector li = new RobustLineIntersector(); - - private Collection segStrings; - private boolean findAllIntersections = false; - private InteriorIntersectionFinder segInt = null; - private boolean isValid = true; - - /** - * Creates a new noding validator for a given set of linework. - * - * @param segStrings a collection of {@link SegmentString}s - */ - public FastNodingValidator(Collection segStrings) - { - this.segStrings = segStrings; - } - - public void setFindAllIntersections(boolean findAllIntersections) - { - this.findAllIntersections = findAllIntersections; - } - - /** - * Gets a list of all intersections found. - * Intersections are represented as {@link Coordinate}s. - * List is empty if none were found. - * - * @return a list of Coordinate - */ - public List getIntersections() - { - return segInt.getIntersections(); - } - - /** - * Checks for an intersection and - * reports if one is found. - * - * @return true if the arrangement contains an interior intersection - */ - public boolean isValid() - { - execute(); - return isValid; - } - - /** - * Returns an error message indicating the segments containing - * the intersection. - * - * @return an error message documenting the intersection location - */ - public String getErrorMessage() - { - if (isValid) return "no intersections found"; - - Coordinate[] intSegs = segInt.getIntersectionSegments(); - return "found non-noded intersection between " - + WKTWriter.toLineString(intSegs[0], intSegs[1]) - + " and " - + WKTWriter.toLineString(intSegs[2], intSegs[3]); - } - - /** - * Checks for an intersection and throws - * a TopologyException if one is found. - * - * @throws TopologyException if an intersection is found - */ - public void checkValid() - { - execute(); - if (! isValid) - throw new TopologyException(getErrorMessage(), segInt.getInteriorIntersection()); - } - - private void execute() - { - if (segInt != null) - return; - checkInteriorIntersections(); - } - - private void checkInteriorIntersections() - { - /** - * MD - It may even be reliable to simply check whether - * end segments (of SegmentStrings) have an interior intersection, - * since noding should have split any true interior intersections already. - */ - isValid = true; - segInt = new InteriorIntersectionFinder(li); - segInt.setFindAllIntersections(findAllIntersections); - MCIndexNoder noder = new MCIndexNoder(); - noder.setSegmentIntersector(segInt); - noder.computeNodes(segStrings); - if (segInt.hasIntersection()) { - isValid = false; - return; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java b/src/main/java/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java deleted file mode 100644 index 435b1b2b2f..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java +++ /dev/null @@ -1,100 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding; - -import java.util.*; - -/** - * Finds if two sets of {@link SegmentString}s intersect. - * Uses indexing for fast performance and to optimize repeated tests - * against a target set of lines. - * Short-circuited to return as soon an intersection is found. - * - * Immutable and thread-safe. - * - * @version 1.7 - */ -public class FastSegmentSetIntersectionFinder -{ - private final SegmentSetMutualIntersector segSetMutInt; - // for testing purposes - // private SimpleSegmentSetMutualIntersector mci; - - /** - * Creates an intersection finder against a given set of segment strings. - * - * @param baseSegStrings the segment strings to search for intersections - */ - public FastSegmentSetIntersectionFinder(Collection baseSegStrings) - { - segSetMutInt = new MCIndexSegmentSetMutualIntersector(baseSegStrings); - } - - /** - * Gets the segment set intersector used by this class. - * This allows other uses of the same underlying indexed structure. - * - * @return the segment set intersector used - */ - public SegmentSetMutualIntersector getSegmentSetIntersector() - { - return segSetMutInt; - } - - /** - * Tests for intersections with a given set of target {@link SegmentString}s. - * - * @param segStrings the SegmentStrings to test - * @return true if an intersection is found - */ - public boolean intersects(Collection segStrings) - { - SegmentIntersectionDetector intFinder = new SegmentIntersectionDetector(); - return intersects(segStrings, intFinder); - } - - /** - * Tests for intersections with a given set of target {@link SegmentString}s. - * using a given SegmentIntersectionDetector. - * - * @param segStrings the SegmentStrings to test - * @param intDetector the intersection detector to use - * @return true if the detector reports intersections - */ - public boolean intersects(Collection segStrings, SegmentIntersectionDetector intDetector) - { - segSetMutInt.process(segStrings, intDetector); - return intDetector.hasIntersection(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java b/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java deleted file mode 100644 index 7fed6c9ee1..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -//import com.vividsolutions.jts.util.Debug; - -/** - * Finds an interior intersection in a set of {@link SegmentString}s, - * if one exists. Only the first intersection found is reported. - * - * @version 1.7 - */ -public class InteriorIntersectionFinder - implements SegmentIntersector -{ - /** - * Creates an intersection finder which tests if there is at least one interior intersection. - * Uses short-circuiting for efficient performance. - * The intersection found is recorded. - * - * @param li a line intersector - * @return a intersection finder which tests if there is at least one interior intersection. - */ - public static InteriorIntersectionFinder createAnyIntersectionFinder(LineIntersector li) - { - return new InteriorIntersectionFinder(li); - } - - /** - * Creates an intersection finder which finds all interior intersections. - * The intersections are recorded for later inspection. - * - * @param li a line intersector - * @return a intersection finder which finds all interior intersections. - */ - public static InteriorIntersectionFinder createAllIntersectionsFinder(LineIntersector li) - { - InteriorIntersectionFinder finder = new InteriorIntersectionFinder(li); - finder.setFindAllIntersections(true); - return finder; - } - - /** - * Creates an intersection finder which counts all interior intersections. - * The intersections are note recorded to reduce memory usage. - * - * @param li a line intersector - * @return a intersection finder which counts all interior intersections. - */ - public static InteriorIntersectionFinder createIntersectionCounter(LineIntersector li) - { - InteriorIntersectionFinder finder = new InteriorIntersectionFinder(li); - finder.setFindAllIntersections(true); - finder.setKeepIntersections(false); - return finder; - } - - private boolean findAllIntersections = false; - private boolean isCheckEndSegmentsOnly = false; - private LineIntersector li; - private Coordinate interiorIntersection = null; - private Coordinate[] intSegments = null; - private List intersections = new ArrayList(); - private int intersectionCount = 0; - private boolean keepIntersections = true; - - /** - * Creates an intersection finder which finds an interior intersection - * if one exists - * - * @param li the LineIntersector to use - */ - public InteriorIntersectionFinder(LineIntersector li) - { - this.li = li; - interiorIntersection = null; - } - - /** - * Sets whether all intersections should be computed. - * When this is false (the default value) - * the value of {@link #isDone()} is true after the first intersection is found. - *

                    - * Default is false. - * - * @param findAllIntersections whether all intersections should be computed - */ - public void setFindAllIntersections(boolean findAllIntersections) - { - this.findAllIntersections = findAllIntersections; - } - - /** - * Sets whether intersection points are recorded. - * If the only need is to count intersection points, this can be set to false. - *

                    - * Default is true. - * - * @param keepIntersections indicates whether intersections should be recorded - */ - public void setKeepIntersections(boolean keepIntersections) - { - this.keepIntersections = keepIntersections; - } - - /** - * Gets the intersections found. - * - * @return a List of {@link Coordinate) - */ - public List getIntersections() - { - return intersections; - } - - /** - * Gets the count of intersections found. - * - * @return the intersection count - */ - public int count() - { - return intersectionCount; - } - - /** - * Sets whether only end segments should be tested for interior intersection. - * This is a performance optimization that may be used if - * the segments have been previously noded by an appropriate algorithm. - * It may be known that any potential noding failures will occur only in - * end segments. - * - * @param isCheckEndSegmentsOnly whether to test only end segments - */ - public void setCheckEndSegmentsOnly(boolean isCheckEndSegmentsOnly) - { - this.isCheckEndSegmentsOnly = isCheckEndSegmentsOnly; - } - - /** - * Tests whether an intersection was found. - * - * @return true if an intersection was found - */ - public boolean hasIntersection() - { - return interiorIntersection != null; - } - - /** - * Gets the computed location of the intersection. - * Due to round-off, the location may not be exact. - * - * @return the coordinate for the intersection location - */ - public Coordinate getInteriorIntersection() - { - return interiorIntersection; - } - - /** - * Gets the endpoints of the intersecting segments. - * - * @return an array of the segment endpoints (p00, p01, p10, p11) - */ - public Coordinate[] getIntersectionSegments() - { - return intSegments; - } - - /** - * This method is called by clients - * of the {@link SegmentIntersector} class to process - * intersections for two segments of the {@link SegmentString}s being intersected. - * Note that some clients (such as MonotoneChains) may optimize away - * this call for segment pairs which they have determined do not intersect - * (e.g. by an disjoint envelope test). - */ - public void processIntersections( - SegmentString e0, int segIndex0, - SegmentString e1, int segIndex1 - ) - { - // short-circuit if intersection already found - if (! findAllIntersections && hasIntersection()) - return; - - // don't bother intersecting a segment with itself - if (e0 == e1 && segIndex0 == segIndex1) return; - - /** - * If enabled, only test end segments (on either segString). - * - */ - if (isCheckEndSegmentsOnly) { - boolean isEndSegPresent = isEndSegment(e0, segIndex0) || isEndSegment(e1, segIndex1); - if (! isEndSegPresent) - return; - } - - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); -//if (li.hasIntersection() && li.isProper()) Debug.println(li); - - if (li.hasIntersection()) { - if (li.isInteriorIntersection()) { - intSegments = new Coordinate[4]; - intSegments[0] = p00; - intSegments[1] = p01; - intSegments[2] = p10; - intSegments[3] = p11; - - interiorIntersection = li.getIntersection(0); - if (keepIntersections) intersections.add(interiorIntersection); - intersectionCount++; - } - } - } - - /** - * Tests whether a segment in a {@link SegmentString} is an end segment. - * (either the first or last). - * - * @param segStr a segment string - * @param index the index of a segment in the segment string - * @return true if the segment is an end segment - */ - private boolean isEndSegment(SegmentString segStr, int index) - { - if (index == 0) return true; - if (index >= segStr.size() - 2) return true; - return false; - } - - public boolean isDone() - { - if (findAllIntersections) return false; - return interiorIntersection != null; - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinderAdder.java b/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinderAdder.java deleted file mode 100644 index ed8c4e77b6..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/InteriorIntersectionFinderAdder.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.util.Debug; - -/** - * Finds interior intersections between line segments in {@link NodedSegmentString}s, - * and adds them as nodes - * using {@link NodedSegmentString#addIntersection(LineIntersector, int, int, int)}. - *

                    - * This class is used primarily for Snap-Rounding. - * For general-purpose noding, use {@link IntersectionAdder}. - * - * @version 1.7 - * @see IntersectionAdder - */ -public class InteriorIntersectionFinderAdder - implements SegmentIntersector -{ - private LineIntersector li; - private final List interiorIntersections; - - - /** - * Creates an intersection finder which finds all proper intersections - * - * @param li the LineIntersector to use - */ - public InteriorIntersectionFinderAdder(LineIntersector li) - { - this.li = li; - interiorIntersections = new ArrayList(); - } - - public List getInteriorIntersections() { return interiorIntersections; } - - /** - * This method is called by clients - * of the {@link SegmentIntersector} class to process - * intersections for two segments of the {@link SegmentString}s being intersected. - * Note that some clients (such as MonotoneChains) may optimize away - * this call for segment pairs which they have determined do not intersect - * (e.g. by an disjoint envelope test). - */ - public void processIntersections( - SegmentString e0, int segIndex0, - SegmentString e1, int segIndex1 - ) - { - // don't bother intersecting a segment with itself - if (e0 == e1 && segIndex0 == segIndex1) return; - - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); -//if (li.hasIntersection() && li.isProper()) Debug.println(li); - - if (li.hasIntersection()) { - if (li.isInteriorIntersection()) { - for (int intIndex = 0; intIndex < li.getIntersectionNum(); intIndex++) { - interiorIntersections.add(li.getIntersection(intIndex)); - } - ((NodedSegmentString) e0).addIntersections(li, segIndex0, 0); - ((NodedSegmentString) e1).addIntersections(li, segIndex1, 1); - } - } - } - - /** - * Always process all intersections - * - * @return false always - */ - public boolean isDone() { return false; } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/noding/IntersectionAdder.java b/src/main/java/com/vividsolutions/jts/noding/IntersectionAdder.java deleted file mode 100644 index a9fd3ba676..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/IntersectionAdder.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Computes the possible intersections between two line segments in {@link NodedSegmentString}s - * and adds them to each string - * using {@link NodedSegmentString#addIntersection(LineIntersector, int, int, int)}. - * - * @version 1.7 - */ -public class IntersectionAdder - implements SegmentIntersector -{ - public static boolean isAdjacentSegments(int i1, int i2) - { - return Math.abs(i1 - i2) == 1; - } - - /** - * These variables keep track of what types of intersections were - * found during ALL edges that have been intersected. - */ - private boolean hasIntersection = false; - private boolean hasProper = false; - private boolean hasProperInterior = false; - private boolean hasInterior = false; - - // the proper intersection point found - private Coordinate properIntersectionPoint = null; - - private LineIntersector li; - private boolean isSelfIntersection; - //private boolean intersectionFound; - public int numIntersections = 0; - public int numInteriorIntersections = 0; - public int numProperIntersections = 0; - - // testing only - public int numTests = 0; - - public IntersectionAdder(LineIntersector li) - { - this.li = li; - } - - public LineIntersector getLineIntersector() { return li; } - - /** - * @return the proper intersection point, or null if none was found - */ - public Coordinate getProperIntersectionPoint() { return properIntersectionPoint; } - - public boolean hasIntersection() { return hasIntersection; } - /** - * A proper intersection is an intersection which is interior to at least two - * line segments. Note that a proper intersection is not necessarily - * in the interior of the entire Geometry, since another edge may have - * an endpoint equal to the intersection, which according to SFS semantics - * can result in the point being on the Boundary of the Geometry. - */ - public boolean hasProperIntersection() { return hasProper; } - /** - * A proper interior intersection is a proper intersection which is not - * contained in the set of boundary nodes set for this SegmentIntersector. - */ - public boolean hasProperInteriorIntersection() { return hasProperInterior; } - /** - * An interior intersection is an intersection which is - * in the interior of some segment. - */ - public boolean hasInteriorIntersection() { return hasInterior; } - - /** - * A trivial intersection is an apparent self-intersection which in fact - * is simply the point shared by adjacent line segments. - * Note that closed edges require a special check for the point shared by the beginning - * and end segments. - */ - private boolean isTrivialIntersection(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) - { - if (e0 == e1) { - if (li.getIntersectionNum() == 1) { - if (isAdjacentSegments(segIndex0, segIndex1)) - return true; - if (e0.isClosed()) { - int maxSegIndex = e0.size() - 1; - if ( (segIndex0 == 0 && segIndex1 == maxSegIndex) - || (segIndex1 == 0 && segIndex0 == maxSegIndex) ) { - return true; - } - } - } - } - return false; - } - - /** - * This method is called by clients - * of the {@link SegmentIntersector} class to process - * intersections for two segments of the {@link SegmentString}s being intersected. - * Note that some clients (such as MonotoneChains) may optimize away - * this call for segment pairs which they have determined do not intersect - * (e.g. by an disjoint envelope test). - */ - public void processIntersections( - SegmentString e0, int segIndex0, - SegmentString e1, int segIndex1 - ) - { - if (e0 == e1 && segIndex0 == segIndex1) return; -numTests++; - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); -//if (li.hasIntersection() && li.isProper()) Debug.println(li); - if (li.hasIntersection()) { - //intersectionFound = true; - numIntersections++; - if (li.isInteriorIntersection()) { - numInteriorIntersections++; - hasInterior = true; -//System.out.println(li); - } - // if the segments are adjacent they have at least one trivial intersection, - // the shared endpoint. Don't bother adding it if it is the - // only intersection. - if (! isTrivialIntersection(e0, segIndex0, e1, segIndex1)) { - hasIntersection = true; - ((NodedSegmentString) e0).addIntersections(li, segIndex0, 0); - ((NodedSegmentString) e1).addIntersections(li, segIndex1, 1); - if (li.isProper()) { - numProperIntersections++; -//Debug.println(li.toString()); Debug.println(li.getIntersection(0)); - //properIntersectionPoint = (Coordinate) li.getIntersection(0).clone(); - hasProper = true; - hasProperInterior = true; - } - } - } - } - - /** - * Always process all intersections - * - * @return false always - */ - public boolean isDone() { return false; } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/IntersectionFinderAdder.java b/src/main/java/com/vividsolutions/jts/noding/IntersectionFinderAdder.java deleted file mode 100644 index 0566e025db..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/IntersectionFinderAdder.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.util.Debug; - -/** - * Finds interior intersections between line segments in {@link NodedSegmentString}s, - * and adds them as nodes - * using {@link NodedSegmentString#addIntersection(LineIntersector, int, int, int)}. - *

                    - * This class is used primarily for Snap-Rounding. - * For general-purpose noding, use {@link IntersectionAdder}. - * - * @version 1.7 - * @see IntersectionAdder - * @deprecated see InteriorIntersectionFinderAdder - */ -public class IntersectionFinderAdder - implements SegmentIntersector -{ - private LineIntersector li; - private final List interiorIntersections; - - - /** - * Creates an intersection finder which finds all proper intersections - * - * @param li the LineIntersector to use - */ - public IntersectionFinderAdder(LineIntersector li) - { - this.li = li; - interiorIntersections = new ArrayList(); - } - - public List getInteriorIntersections() { return interiorIntersections; } - - /** - * This method is called by clients - * of the {@link SegmentIntersector} class to process - * intersections for two segments of the {@link SegmentString}s being intersected. - * Note that some clients (such as MonotoneChains) may optimize away - * this call for segment pairs which they have determined do not intersect - * (e.g. by an disjoint envelope test). - */ - public void processIntersections( - SegmentString e0, int segIndex0, - SegmentString e1, int segIndex1 - ) - { - // don't bother intersecting a segment with itself - if (e0 == e1 && segIndex0 == segIndex1) return; - - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); -//if (li.hasIntersection() && li.isProper()) Debug.println(li); - - if (li.hasIntersection()) { - if (li.isInteriorIntersection()) { - for (int intIndex = 0; intIndex < li.getIntersectionNum(); intIndex++) { - interiorIntersections.add(li.getIntersection(intIndex)); - } - ((NodedSegmentString) e0).addIntersections(li, segIndex0, 0); - ((NodedSegmentString) e1).addIntersections(li, segIndex1, 1); - } - } - } - - /** - * Always process all intersections - * - * @return false always - */ - public boolean isDone() { return false; } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/noding/IteratedNoder.java b/src/main/java/com/vividsolutions/jts/noding/IteratedNoder.java deleted file mode 100644 index ea4af5fd9d..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/IteratedNoder.java +++ /dev/null @@ -1,140 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import java.util.*; - -/** - * Nodes a set of {@link NodedSegmentString}s completely. - * The set of segment strings is fully noded; - * i.e. noding is repeated until no further - * intersections are detected. - *

                    - * Iterated noding using a FLOATING precision model is not guaranteed to converge, - * due to roundoff error. - * This problem is detected and an exception is thrown. - * Clients can choose to rerun the noding using a lower precision model. - * - * @version 1.7 - */ -public class IteratedNoder - implements Noder -{ - public static final int MAX_ITER = 5; - - private PrecisionModel pm; - private LineIntersector li; - private Collection nodedSegStrings; - private int maxIter = MAX_ITER; - - public IteratedNoder(PrecisionModel pm) - { - li = new RobustLineIntersector(); - this.pm = pm; - li.setPrecisionModel(pm); - } - - /** - * Sets the maximum number of noding iterations performed before - * the noding is aborted. - * Experience suggests that this should rarely need to be changed - * from the default. - * The default is MAX_ITER. - * - * @param maxIter the maximum number of iterations to perform - */ - public void setMaximumIterations(int maxIter) - { - this.maxIter = maxIter; - } - - public Collection getNodedSubstrings() { return nodedSegStrings; } - - /** - * Fully nodes a list of {@link SegmentString}s, i.e. peforms noding iteratively - * until no intersections are found between segments. - * Maintains labelling of edges correctly through - * the noding. - * - * @param segStrings a collection of SegmentStrings to be noded - * @throws TopologyException if the iterated noding fails to converge. - */ - public void computeNodes(Collection segStrings) - throws TopologyException - { - int[] numInteriorIntersections = new int[1]; - nodedSegStrings = segStrings; - int nodingIterationCount = 0; - int lastNodesCreated = -1; - do { - node(nodedSegStrings, numInteriorIntersections); - nodingIterationCount++; - int nodesCreated = numInteriorIntersections[0]; - - /** - * Fail if the number of nodes created is not declining. - * However, allow a few iterations at least before doing this - */ -//System.out.println("# nodes created: " + nodesCreated); - if (lastNodesCreated > 0 - && nodesCreated >= lastNodesCreated - && nodingIterationCount > maxIter) { - throw new TopologyException("Iterated noding failed to converge after " - + nodingIterationCount + " iterations"); - } - lastNodesCreated = nodesCreated; - - } while (lastNodesCreated > 0); -//System.out.println("# nodings = " + nodingIterationCount); - } - - -/** - * Node the input segment strings once - * and create the split edges between the nodes - */ - private void node(Collection segStrings, int[] numInteriorIntersections) - { - IntersectionAdder si = new IntersectionAdder(li); - MCIndexNoder noder = new MCIndexNoder(); - noder.setSegmentIntersector(si); - noder.computeNodes(segStrings); - nodedSegStrings = noder.getNodedSubstrings(); - numInteriorIntersections[0] = si.numInteriorIntersections; -//System.out.println("# intersection tests: " + si.numTests); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/MCIndexNoder.java b/src/main/java/com/vividsolutions/jts/noding/MCIndexNoder.java deleted file mode 100644 index d76fbef4b6..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/MCIndexNoder.java +++ /dev/null @@ -1,140 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.index.*; -import com.vividsolutions.jts.index.chain.*; -import com.vividsolutions.jts.index.strtree.*; -import java.util.*; - -/** - * Nodes a set of {@link SegmentString}s using a index based - * on {@link MonotoneChain}s and a {@link SpatialIndex}. - * The {@link SpatialIndex} used should be something that supports - * envelope (range) queries efficiently (such as a Quadtree} - * or {@link STRtree} (which is the default index provided). - * - * @version 1.7 - */ -public class MCIndexNoder - extends SinglePassNoder -{ - private List monoChains = new ArrayList(); - private SpatialIndex index= new STRtree(); - private int idCounter = 0; - private Collection nodedSegStrings; - // statistics - private int nOverlaps = 0; - - public MCIndexNoder() - { - } - public MCIndexNoder(SegmentIntersector si) - { - super(si); - } - - public List getMonotoneChains() { return monoChains; } - - public SpatialIndex getIndex() { return index; } - - public Collection getNodedSubstrings() - { - return NodedSegmentString.getNodedSubstrings(nodedSegStrings); - } - - public void computeNodes(Collection inputSegStrings) - { - this.nodedSegStrings = inputSegStrings; - for (Iterator i = inputSegStrings.iterator(); i.hasNext(); ) { - add((SegmentString) i.next()); - } - intersectChains(); -//System.out.println("MCIndexNoder: # chain overlaps = " + nOverlaps); - } - - private void intersectChains() - { - MonotoneChainOverlapAction overlapAction = new SegmentOverlapAction(segInt); - - for (Iterator i = monoChains.iterator(); i.hasNext(); ) { - MonotoneChain queryChain = (MonotoneChain) i.next(); - List overlapChains = index.query(queryChain.getEnvelope()); - for (Iterator j = overlapChains.iterator(); j.hasNext(); ) { - MonotoneChain testChain = (MonotoneChain) j.next(); - /** - * following test makes sure we only compare each pair of chains once - * and that we don't compare a chain to itself - */ - if (testChain.getId() > queryChain.getId()) { - queryChain.computeOverlaps(testChain, overlapAction); - nOverlaps++; - } - // short-circuit if possible - if (segInt.isDone()) - return; - } - } - } - - private void add(SegmentString segStr) - { - List segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr); - for (Iterator i = segChains.iterator(); i.hasNext(); ) { - MonotoneChain mc = (MonotoneChain) i.next(); - mc.setId(idCounter++); - index.insert(mc.getEnvelope(), mc); - monoChains.add(mc); - } - } - - public class SegmentOverlapAction - extends MonotoneChainOverlapAction - { - private SegmentIntersector si = null; - - public SegmentOverlapAction(SegmentIntersector si) - { - this.si = si; - } - - public void overlap(MonotoneChain mc1, int start1, MonotoneChain mc2, int start2) - { - SegmentString ss1 = (SegmentString) mc1.getContext(); - SegmentString ss2 = (SegmentString) mc2.getContext(); - si.processIntersections(ss1, start1, ss2, start2); - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java b/src/main/java/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java deleted file mode 100644 index d631215c0d..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; - -import com.vividsolutions.jts.index.SpatialIndex; -import com.vividsolutions.jts.index.chain.*; -import com.vividsolutions.jts.index.strtree.STRtree; -import com.vividsolutions.jts.noding.SegmentIntersector; -import com.vividsolutions.jts.noding.SegmentString; - -/** - * Intersects two sets of {@link SegmentString}s using a index based - * on {@link MonotoneChain}s and a {@link SpatialIndex}. - * - * Thread-safe and immutable. - * - * @version 1.7 - */ -public class MCIndexSegmentSetMutualIntersector implements SegmentSetMutualIntersector -{ - /** - * The {@link SpatialIndex} used should be something that supports - * envelope (range) queries efficiently (such as a - * {@link com.vividsolutions.jts.index.quadtree.Quadtree} - * or {@link STRtree}. - */ - private STRtree index = new STRtree(); - - /** - * Constructs a new intersector for a given set of {@link SegmentStrings}. - * - * @param baseSegStrings the base segment strings to intersect - */ - public MCIndexSegmentSetMutualIntersector(Collection baseSegStrings) - { - initBaseSegments(baseSegStrings); - } - - /** - * Gets the index constructed over the base segment strings. - * - * NOTE: To retain thread-safety, treat returned value as immutable! - * - * @return the constructed index - */ - public SpatialIndex getIndex() { return index; } - - private void initBaseSegments(Collection segStrings) - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - addToIndex((SegmentString) i.next()); - } - // build index to ensure thread-safety - index.build(); - } - - private void addToIndex(SegmentString segStr) - { - List segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr); - for (Iterator i = segChains.iterator(); i.hasNext(); ) { - MonotoneChain mc = (MonotoneChain) i.next(); - index.insert(mc.getEnvelope(), mc); - } - } - - /** - * Calls {@link SegmentIntersector#processIntersections(SegmentString, int, SegmentString, int)} - * for all candidate intersections between - * the given collection of SegmentStrings and the set of indexed segments. - * - * @param a set of segments to intersect - * @param the segment intersector to use - */ - public void process(Collection segStrings, SegmentIntersector segInt) - { - List monoChains = new ArrayList(); - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - addToMonoChains((SegmentString) i.next(), monoChains); - } - intersectChains(monoChains, segInt); -// System.out.println("MCIndexBichromaticIntersector: # chain overlaps = " + nOverlaps); -// System.out.println("MCIndexBichromaticIntersector: # oct chain overlaps = " + nOctOverlaps); - } - - private void addToMonoChains(SegmentString segStr, List monoChains) - { - List segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr); - for (Iterator i = segChains.iterator(); i.hasNext(); ) { - MonotoneChain mc = (MonotoneChain) i.next(); - monoChains.add(mc); - } - } - - private void intersectChains(List monoChains, SegmentIntersector segInt) - { - MonotoneChainOverlapAction overlapAction = new SegmentOverlapAction(segInt); - - for (Iterator i = monoChains.iterator(); i.hasNext(); ) { - MonotoneChain queryChain = (MonotoneChain) i.next(); - List overlapChains = index.query(queryChain.getEnvelope()); - for (Iterator j = overlapChains.iterator(); j.hasNext(); ) { - MonotoneChain testChain = (MonotoneChain) j.next(); - queryChain.computeOverlaps(testChain, overlapAction); - if (segInt.isDone()) return; - } - } - } - - public class SegmentOverlapAction - extends MonotoneChainOverlapAction - { - private SegmentIntersector si = null; - - public SegmentOverlapAction(SegmentIntersector si) - { - this.si = si; - } - - public void overlap(MonotoneChain mc1, int start1, MonotoneChain mc2, int start2) - { - SegmentString ss1 = (SegmentString) mc1.getContext(); - SegmentString ss2 = (SegmentString) mc2.getContext(); - si.processIntersections(ss1, start1, ss2, start2); - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/NodableSegmentString.java b/src/main/java/com/vividsolutions/jts/noding/NodableSegmentString.java deleted file mode 100644 index beafc1a269..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/NodableSegmentString.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * An interface for classes which support adding nodes to - * a segment string. - * - * @author Martin Davis - */ -public interface NodableSegmentString - extends SegmentString -{ - /** - * Adds an intersection node for a given point and segment to this segment string. - * - * @param intPt the location of the intersection - * @param segmentIndex the index of the segment containing the intersection - */ - public void addIntersection(Coordinate intPt, int segmentIndex); -} diff --git a/src/main/java/com/vividsolutions/jts/noding/NodedSegmentString.java b/src/main/java/com/vividsolutions/jts/noding/NodedSegmentString.java deleted file mode 100644 index f834cfbc61..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/NodedSegmentString.java +++ /dev/null @@ -1,212 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * Represents a list of contiguous line segments, - * and supports noding the segments. - * The line segments are represented by an array of {@link Coordinate}s. - * Intended to optimize the noding of contiguous segments by - * reducing the number of allocated objects. - * SegmentStrings can carry a context object, which is useful - * for preserving topological or parentage information. - * All noded substrings are initialized with the same context object. - * - * @version 1.7 - */ -public class NodedSegmentString - implements NodableSegmentString -{ - /** - * Gets the {@link SegmentString}s which result from splitting this string at node points. - * - * @param segStrings a Collection of NodedSegmentStrings - * @return a Collection of NodedSegmentStrings representing the substrings - */ - public static List getNodedSubstrings(Collection segStrings) - { - List resultEdgelist = new ArrayList(); - getNodedSubstrings(segStrings, resultEdgelist); - return resultEdgelist; - } - - /** - * Adds the noded {@link SegmentString}s which result from splitting this string at node points. - * - * @param segStrings a Collection of NodedSegmentStrings - * @param resultEdgelist a List which will collect the NodedSegmentStrings representing the substrings - */ - public static void getNodedSubstrings(Collection segStrings, Collection resultEdgelist) - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - NodedSegmentString ss = (NodedSegmentString) i.next(); - ss.getNodeList().addSplitEdges(resultEdgelist); - } - } - - private SegmentNodeList nodeList = new SegmentNodeList(this); - private Coordinate[] pts; - private Object data; - - /** - * Creates a new segment string from a list of vertices. - * - * @param pts the vertices of the segment string - * @param data the user-defined data of this segment string (may be null) - */ - public NodedSegmentString(Coordinate[] pts, Object data) - { - this.pts = pts; - this.data = data; - } - - /** - * Gets the user-defined data for this segment string. - * - * @return the user-defined data - */ - public Object getData() { return data; } - - /** - * Sets the user-defined data for this segment string. - * - * @param data an Object containing user-defined data - */ - public void setData(Object data) { this.data = data; } - - public SegmentNodeList getNodeList() { return nodeList; } - public int size() { return pts.length; } - public Coordinate getCoordinate(int i) { return pts[i]; } - public Coordinate[] getCoordinates() { return pts; } - - public boolean isClosed() - { - return pts[0].equals(pts[pts.length - 1]); - } - - /** - * Gets the octant of the segment starting at vertex index. - * - * @param index the index of the vertex starting the segment. Must not be - * the last index in the vertex list - * @return the octant of the segment at the vertex - */ - public int getSegmentOctant(int index) - { - if (index == pts.length - 1) return -1; - return safeOctant(getCoordinate(index), getCoordinate(index + 1)); -// return Octant.octant(getCoordinate(index), getCoordinate(index + 1)); - } - - private int safeOctant(Coordinate p0, Coordinate p1) - { - if (p0.equals2D(p1)) return 0; - return Octant.octant(p0, p1); - } - - /** - * Adds EdgeIntersections for one or both - * intersections found for a segment of an edge to the edge intersection list. - */ - public void addIntersections(LineIntersector li, int segmentIndex, int geomIndex) - { - for (int i = 0; i < li.getIntersectionNum(); i++) { - addIntersection(li, segmentIndex, geomIndex, i); - } - } - /** - * Add an SegmentNode for intersection intIndex. - * An intersection that falls exactly on a vertex - * of the SegmentString is normalized - * to use the higher of the two possible segmentIndexes - */ - public void addIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex) - { - Coordinate intPt = new Coordinate(li.getIntersection(intIndex)); - addIntersection(intPt, segmentIndex); - } - - /** - * Adds an intersection node for a given point and segment to this segment string. - * - * @param intPt the location of the intersection - * @param segmentIndex the index of the segment containing the intersection - */ - public void addIntersection(Coordinate intPt, int segmentIndex) { - addIntersectionNode(intPt, segmentIndex); - } - - /** - * Adds an intersection node for a given point and segment to this segment string. - * If an intersection already exists for this exact location, the existing - * node will be returned. - * - * @param intPt the location of the intersection - * @param segmentIndex the index of the segment containing the intersection - * @return the intersection node for the point - */ - public SegmentNode addIntersectionNode(Coordinate intPt, int segmentIndex) { - int normalizedSegmentIndex = segmentIndex; - //Debug.println("edge intpt: " + intPt + " dist: " + dist); - // normalize the intersection point location - int nextSegIndex = normalizedSegmentIndex + 1; - if (nextSegIndex < pts.length) { - Coordinate nextPt = pts[nextSegIndex]; - //Debug.println("next pt: " + nextPt); - - // Normalize segment index if intPt falls on vertex - // The check for point equality is 2D only - Z values are ignored - if (intPt.equals2D(nextPt)) { - //Debug.println("normalized distance"); - normalizedSegmentIndex = nextSegIndex; - } - } - /** - * Add the intersection point to edge intersection list. - */ - SegmentNode ei = nodeList.add(intPt, normalizedSegmentIndex); - return ei; - } - - public String toString() - { - return WKTWriter.toLineString(new CoordinateArraySequence(pts)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/Noder.java b/src/main/java/com/vividsolutions/jts/noding/Noder.java deleted file mode 100644 index 47cc821bda..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/Noder.java +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; - -/** - * Computes all intersections between segments in a set of {@link SegmentString}s. - * Intersections found are represented as {@link SegmentNode}s and added to the - * {@link SegmentString}s in which they occur. - * As a final step in the noding a new set of segment strings split - * at the nodes may be returned. - * - * @version 1.7 - */ -public interface Noder -{ - - /** - * Computes the noding for a collection of {@link SegmentString}s. - * Some Noders may add all these nodes to the input SegmentStrings; - * others may only add some or none at all. - * - * @param segStrings a collection of {@link SegmentString}s to node - */ - void computeNodes(Collection segStrings); - - /** - * Returns a {@link Collection} of fully noded {@link SegmentString}s. - * The SegmentStrings have the same context as their parent. - * - * @return a Collection of SegmentStrings - */ - Collection getNodedSubstrings(); - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/NodingValidator.java b/src/main/java/com/vividsolutions/jts/noding/NodingValidator.java deleted file mode 100644 index 5657a70818..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/NodingValidator.java +++ /dev/null @@ -1,180 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * Validates that a collection of {@link SegmentString}s is correctly noded. - * Throws an appropriate exception if an noding error is found. - * - * @version 1.7 - */ -public class NodingValidator { - - private LineIntersector li = new RobustLineIntersector(); - - private Collection segStrings; - - public NodingValidator(Collection segStrings) - { - this.segStrings = segStrings; - } - - public void checkValid() - { - // MD - is this call required? Or could it be done in the Interior Intersection code? - checkEndPtVertexIntersections(); - checkInteriorIntersections(); - checkCollapses(); - } - - /** - * Checks if a segment string contains a segment pattern a-b-a (which implies a self-intersection) - */ - private void checkCollapses() - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString ss = (SegmentString) i.next(); - checkCollapses(ss); - } - } - - private void checkCollapses(SegmentString ss) - { - Coordinate[] pts = ss.getCoordinates(); - for (int i = 0; i < pts.length - 2; i++) { - checkCollapse(pts[i], pts[i + 1], pts[i + 2]); - } - } - - private void checkCollapse(Coordinate p0, Coordinate p1, Coordinate p2) - { - if (p0.equals(p2)) - throw new RuntimeException("found non-noded collapse at " - + Debug.toLine(p0, p1, p2)); - } - - /** - * Checks all pairs of segments for intersections at an interior point of a segment - */ - private void checkInteriorIntersections() - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString ss0 = (SegmentString) i.next(); - for (Iterator j = segStrings.iterator(); j.hasNext(); ) { - SegmentString ss1 = (SegmentString) j.next(); - - checkInteriorIntersections(ss0, ss1); - } - } - } - - private void checkInteriorIntersections(SegmentString ss0, SegmentString ss1) - { - Coordinate[] pts0 = ss0.getCoordinates(); - Coordinate[] pts1 = ss1.getCoordinates(); - for (int i0 = 0; i0 < pts0.length - 1; i0++) { - for (int i1 = 0; i1 < pts1.length - 1; i1++) { - checkInteriorIntersections(ss0, i0, ss1, i1); - } - } - } - - private void checkInteriorIntersections(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1) - { - if (e0 == e1 && segIndex0 == segIndex1) return; -//numTests++; - Coordinate p00 = e0.getCoordinates()[segIndex0]; - Coordinate p01 = e0.getCoordinates()[segIndex0 + 1]; - Coordinate p10 = e1.getCoordinates()[segIndex1]; - Coordinate p11 = e1.getCoordinates()[segIndex1 + 1]; - - li.computeIntersection(p00, p01, p10, p11); - if (li.hasIntersection()) { - - if (li.isProper() - || hasInteriorIntersection(li, p00, p01) - || hasInteriorIntersection(li, p10, p11)) { - throw new RuntimeException("found non-noded intersection at " - + p00 + "-" + p01 - + " and " - + p10 + "-" + p11); - } - } - } - /** - *@return true if there is an intersection point which is not an endpoint of the segment p0-p1 - */ - private boolean hasInteriorIntersection(LineIntersector li, Coordinate p0, Coordinate p1) - { - for (int i = 0; i < li.getIntersectionNum(); i++) { - Coordinate intPt = li.getIntersection(i); - if (! (intPt.equals(p0) || intPt.equals(p1))) - return true; - } - return false; - } - - /** - * Checks for intersections between an endpoint of a segment string - * and an interior vertex of another segment string - */ - private void checkEndPtVertexIntersections() - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString ss = (SegmentString) i.next(); - Coordinate[] pts = ss.getCoordinates(); - checkEndPtVertexIntersections(pts[0], segStrings); - checkEndPtVertexIntersections(pts[pts.length - 1], segStrings); - } - } - - private void checkEndPtVertexIntersections(Coordinate testPt, Collection segStrings) - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString ss = (SegmentString) i.next(); - Coordinate[] pts = ss.getCoordinates(); - for (int j = 1; j < pts.length - 1; j++) { - if (pts[j].equals(testPt)) - throw new RuntimeException("found endpt/interior pt intersection at index " + j + " :pt " + testPt); - } - } - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/Octant.java b/src/main/java/com/vividsolutions/jts/noding/Octant.java deleted file mode 100644 index c247ff6761..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/Octant.java +++ /dev/null @@ -1,110 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.geom.Coordinate; -/** - * Methods for computing and working with octants of the Cartesian plane - * Octants are numbered as follows: - *

                    - *  \2|1/
                    - * 3 \|/ 0
                    - * ---+--
                    - * 4 /|\ 7
                    - *  /5|6\
                    - * 
                    - * If line segments lie along a coordinate axis, the octant is the lower of the two
                    - * possible values.
                    - *
                    - * @version 1.7
                    - */
                    -public class Octant {
                    -
                    -  /**
                    -   * Returns the octant of a directed line segment (specified as x and y
                    -   * displacements, which cannot both be 0).
                    -   */
                    -  public static int octant(double dx, double dy)
                    -  {
                    -    if (dx == 0.0 && dy == 0.0)
                    -      throw new IllegalArgumentException("Cannot compute the octant for point ( "+ dx + ", " + dy + " )" );
                    -
                    -    double adx = Math.abs(dx);
                    -    double ady = Math.abs(dy);
                    -
                    -    if (dx >= 0) {
                    -      if (dy >= 0) {
                    -        if (adx >= ady)
                    -          return 0;
                    -        else
                    -          return 1;
                    -      }
                    -      else { // dy < 0
                    -        if (adx >= ady)
                    -          return 7;
                    -        else
                    -          return 6;
                    -      }
                    -    }
                    -    else { // dx < 0
                    -      if (dy >= 0) {
                    -        if (adx >= ady)
                    -          return 3;
                    -        else
                    -          return 2;
                    -      }
                    -      else { // dy < 0
                    -        if (adx >= ady)
                    -          return 4;
                    -        else
                    -          return 5;
                    -      }
                    -    }
                    -  }
                    -
                    -  /**
                    -   * Returns the octant of a directed line segment from p0 to p1.
                    -   */
                    -  public static int octant(Coordinate p0, Coordinate p1)
                    -  {
                    -    double dx = p1.x - p0.x;
                    -    double dy = p1.y - p0.y;
                    -    if (dx == 0.0 && dy == 0.0)
                    -      throw new IllegalArgumentException("Cannot compute the octant for two identical points " + p0);
                    -    return octant(dx, dy);
                    -  }
                    -
                    -  private Octant() {
                    -  }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/OrientedCoordinateArray.java b/src/main/java/com/vividsolutions/jts/noding/OrientedCoordinateArray.java
                    deleted file mode 100644
                    index 4e51155ccd..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/OrientedCoordinateArray.java
                    +++ /dev/null
                    @@ -1,131 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import java.util.*;
                    -import com.vividsolutions.jts.geom.*;
                    -
                    -/**
                    - * Allows comparing {@link Coordinate} arrays
                    - * in an orientation-independent way.
                    - *
                    - * @author Martin Davis
                    - * @version 1.7
                    - */
                    -public class OrientedCoordinateArray
                    -    implements Comparable
                    -{
                    -  private Coordinate[] pts;
                    -  private boolean orientation;
                    -
                    -  /**
                    -   * Creates a new {@link OrientedCoordinateArray}
                    -   * for the given {@link Coordinate} array.
                    -   *
                    -   * @param pts the coordinates to orient
                    -   */
                    -  public OrientedCoordinateArray(Coordinate[] pts)
                    -  {
                    -    this.pts = pts;
                    -    orientation = orientation(pts);
                    -  }
                    -
                    -  /**
                    -   * Computes the canonical orientation for a coordinate array.
                    -   *
                    -   * @param pts the array to test
                    -   * @return true if the points are oriented forwards
                    -   * or false
                    - * Clients should be aware that rescaling can involve loss of precision,
                    - * which can cause zero-length line segments to be created.
                    - * These in turn can cause problems when used to build a planar graph.
                    - * This situation should be checked for and collapsed segments removed if necessary.
                    - *
                    - * @version 1.7
                    - */
                    -public class ScaledNoder
                    -    implements Noder
                    -{
                    -  private Noder noder;
                    -  private double scaleFactor;
                    -  private double offsetX;
                    -  private double offsetY;
                    -  private boolean isScaled = false;
                    -
                    -  public ScaledNoder(Noder noder, double scaleFactor) {
                    -    this(noder, scaleFactor, 0, 0);
                    -  }
                    -
                    -  public ScaledNoder(Noder noder, double scaleFactor, double offsetX, double offsetY) {
                    -    this.noder = noder;
                    -    this.scaleFactor = scaleFactor;
                    -    // no need to scale if input precision is already integral
                    -    isScaled = ! isIntegerPrecision();
                    -  }
                    -
                    -  public boolean isIntegerPrecision() { return scaleFactor == 1.0; }
                    -
                    -  public Collection getNodedSubstrings()
                    -  {
                    -    Collection splitSS = noder.getNodedSubstrings();
                    -    if (isScaled) rescale(splitSS);
                    -    return splitSS;
                    -  }
                    -
                    -  public void computeNodes(Collection inputSegStrings)
                    -  {
                    -    Collection intSegStrings = inputSegStrings;
                    -    if (isScaled)
                    -      intSegStrings = scale(inputSegStrings);
                    -    noder.computeNodes(intSegStrings);
                    -  }
                    -
                    -  private Collection scale(Collection segStrings)
                    -  {
                    -//  	System.out.println("Scaled: scaleFactor = " + scaleFactor);
                    -    return CollectionUtil.transform(segStrings,
                    -                                    new CollectionUtil.Function() {
                    -      public Object execute(Object obj) {
                    -        SegmentString ss = (SegmentString) obj;
                    -        return new NodedSegmentString(scale(ss.getCoordinates()), ss.getData());
                    -      }
                    -                                    }
                    -      );
                    -  }
                    -
                    -  private Coordinate[] scale(Coordinate[] pts)
                    -  {
                    -    Coordinate[] roundPts = new Coordinate[pts.length];
                    -    for (int i = 0; i < pts.length; i++) {
                    -      roundPts[i] = new Coordinate(
                    -          Math.round((pts[i].x - offsetX) * scaleFactor),
                    -          Math.round((pts[i].y - offsetY) * scaleFactor),
                    -          pts[i].z
                    -        );
                    -    }
                    -    Coordinate[] roundPtsNoDup = CoordinateArrays.removeRepeatedPoints(roundPts);
                    -    return roundPtsNoDup;
                    -  }
                    -
                    -  //private double scale(double val) { return (double) Math.round(val * scaleFactor); }
                    -
                    -  private void rescale(Collection segStrings)
                    -  {
                    -//  	System.out.println("Rescaled: scaleFactor = " + scaleFactor);
                    -  	CollectionUtil.apply(segStrings,
                    -  			new CollectionUtil.Function() {
                    -  		public Object execute(Object obj) {
                    -  			SegmentString ss = (SegmentString) obj;
                    -  			rescale(ss.getCoordinates());
                    -  			return null;
                    -  		}
                    -  	}
                    -  	);
                    -  }
                    -
                    -  private void rescale(Coordinate[] pts)
                    -  {
                    -    Coordinate p0 = null;
                    -    Coordinate p1 = null;
                    -    
                    -    if (pts.length == 2) {
                    -      p0 = new Coordinate(pts[0]);
                    -      p1 = new Coordinate(pts[1]);
                    -    }
                    -
                    -    for (int i = 0; i < pts.length; i++) {
                    -      pts[i].x = pts[i].x / scaleFactor + offsetX;
                    -      pts[i].y = pts[i].y / scaleFactor + offsetY;
                    -    }
                    -    
                    -    if (pts.length == 2 && pts[0].equals2D(pts[1])) {
                    -      System.out.println(pts);
                    -    }
                    -  }
                    -
                    -  //private double rescale(double val) { return val / scaleFactor; }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java b/src/main/java/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java
                    deleted file mode 100644
                    index af588276d5..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java
                    +++ /dev/null
                    @@ -1,237 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import com.vividsolutions.jts.algorithm.LineIntersector;
                    -import com.vividsolutions.jts.algorithm.RobustLineIntersector;
                    -import com.vividsolutions.jts.geom.Coordinate;
                    -
                    -/**
                    - * Detects and records an intersection between two {@link SegmentString}s,
                    - * if one exists.  Only a single intersection is recorded.
                    - * This strategy can be configured to search for proper intersections>/b>.
                    - * In this case, the presence of any kind of intersection will still be recorded,
                    - * but searching will continue until either a proper intersection has been found
                    - * or no intersections are detected.
                    - *
                    - * @version 1.7
                    - */
                    -public class SegmentIntersectionDetector
                    -    implements SegmentIntersector
                    -{
                    -  private LineIntersector li;
                    -  private boolean findProper = false;
                    -  private boolean findAllTypes = false;
                    -  
                    -  private boolean hasIntersection = false;
                    -  private boolean hasProperIntersection = false;
                    -  private boolean hasNonProperIntersection = false;
                    -  
                    -  private Coordinate intPt = null;
                    -  private Coordinate[] intSegments = null;
                    -
                    -  /**
                    -   * Creates an intersection finder using a {@link RobustLineIntersector}.
                    -   */
                    -  public SegmentIntersectionDetector()
                    -  {
                    -    this(new RobustLineIntersector());
                    -  }
                    -
                    -  /**
                    -   * Creates an intersection finder using a given LineIntersector.
                    -   *
                    -   * @param li the LineIntersector to use
                    -   */
                    -  public SegmentIntersectionDetector(LineIntersector li)
                    -  {
                    -    this.li = li;
                    -  }
                    -
                    -  /**
                    -   * Sets whether processing must continue until a proper intersection is found.
                    -   * 
                    -   * @param findProper true if processing should continue until a proper intersection is found
                    -   */
                    -  public void setFindProper(boolean findProper)
                    -  {
                    -    this.findProper = findProper;
                    -  }
                    -  
                    -  /**
                    -   * Sets whether processing can terminate once any intersection is found.
                    -   * 
                    -   * @param findAllTypes true if processing can terminate once any intersection is found.
                    -   */
                    -  public void setFindAllIntersectionTypes(boolean findAllTypes)
                    -  {
                    -    this.findAllTypes = findAllTypes;
                    -  }
                    -  
                    -  /**
                    -   * Tests whether an intersection was found.
                    -   * 
                    -   * @return true if an intersection was found
                    -   */
                    -  public boolean hasIntersection() 
                    -  { 
                    -  	return hasIntersection; 
                    -  }
                    -  
                    -  /**
                    -   * Tests whether a proper intersection was found.
                    -   * 
                    -   * @return true if a proper intersection was found
                    -   */
                    -  public boolean hasProperIntersection() 
                    -  { 
                    -    return hasProperIntersection; 
                    -  }
                    -  
                    -  /**
                    -   * Tests whether a non-proper intersection was found.
                    -   * 
                    -   * @return true if a non-proper intersection was found
                    -   */
                    -  public boolean hasNonProperIntersection() 
                    -  { 
                    -    return hasNonProperIntersection; 
                    -  }
                    -  
                    -  /**
                    -   * Gets the computed location of the intersection.
                    -   * Due to round-off, the location may not be exact.
                    -   * 
                    -   * @return the coordinate for the intersection location
                    -   */
                    -  public Coordinate getIntersection()  
                    -  {    
                    -  	return intPt;  
                    -  }
                    -
                    -
                    -  /**
                    -   * Gets the endpoints of the intersecting segments.
                    -   * 
                    -   * @return an array of the segment endpoints (p00, p01, p10, p11)
                    -   */
                    -  public Coordinate[] getIntersectionSegments()
                    -  {
                    -  	return intSegments;
                    -  }
                    -  
                    -  /**
                    -   * This method is called by clients
                    -   * of the {@link SegmentIntersector} class to process
                    -   * intersections for two segments of the {@link SegmentString}s being intersected.
                    -   * Note that some clients (such as MonotoneChains) may optimize away
                    -   * this call for segment pairs which they have determined do not intersect
                    -   * (e.g. by an disjoint envelope test).
                    -   */
                    -  public void processIntersections(
                    -      SegmentString e0,  int segIndex0,
                    -      SegmentString e1,  int segIndex1
                    -      )
                    -  {  	
                    -    // don't bother intersecting a segment with itself
                    -    if (e0 == e1 && segIndex0 == segIndex1) return;
                    -    
                    -    Coordinate p00 = e0.getCoordinates()[segIndex0];
                    -    Coordinate p01 = e0.getCoordinates()[segIndex0 + 1];
                    -    Coordinate p10 = e1.getCoordinates()[segIndex1];
                    -    Coordinate p11 = e1.getCoordinates()[segIndex1 + 1];
                    -    
                    -    li.computeIntersection(p00, p01, p10, p11);
                    -//  if (li.hasIntersection() && li.isProper()) Debug.println(li);
                    -
                    -    if (li.hasIntersection()) {
                    -			// System.out.println(li);
                    -    	
                    -    	// record intersection info
                    -			hasIntersection = true;
                    -			
                    -			boolean isProper = li.isProper();
                    -			if (isProper)
                    -				hasProperIntersection = true;
                    -      if (! isProper)
                    -        hasNonProperIntersection = true;
                    -			
                    -			/**
                    -			 * If this is the kind of intersection we are searching for
                    -			 * OR no location has yet been recorded
                    -			 * save the location data
                    -			 */
                    -			boolean saveLocation = true;
                    -			if (findProper && ! isProper) saveLocation = false;
                    -			
                    -			if (intPt == null || saveLocation) {
                    -
                    -				// record intersection location (approximate)
                    -				intPt = li.getIntersection(0);
                    -
                    -				// record intersecting segments
                    -				intSegments = new Coordinate[4];
                    -				intSegments[0] = p00;
                    -				intSegments[1] = p01;
                    -				intSegments[2] = p10;
                    -				intSegments[3] = p11;
                    -			}
                    -		}
                    -  }
                    -  
                    -  /**
                    -   * Tests whether processing can terminate,
                    -   * because all required information has been obtained
                    -   * (e.g. an intersection of the desired type has been detected).
                    -   * 
                    -   * @return true if processing can terminate
                    -   */
                    -  public boolean isDone()
                    -  { 
                    -    /**
                    -     * If finding all types, we can stop
                    -     * when both possible types have been found.
                    -     */
                    -    if (findAllTypes) {
                    -      return hasProperIntersection && hasNonProperIntersection;
                    -    }
                    -    
                    -  	/**
                    -  	 * If searching for a proper intersection, only stop if one is found
                    -  	 */
                    -  	if (findProper) {
                    -  		return hasProperIntersection;
                    -  	}
                    -  	return hasIntersection;
                    -  }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentIntersector.java b/src/main/java/com/vividsolutions/jts/noding/SegmentIntersector.java
                    deleted file mode 100644
                    index 4a122dc9c0..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentIntersector.java
                    +++ /dev/null
                    @@ -1,72 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import java.util.*;
                    -import com.vividsolutions.jts.geom.*;
                    -import com.vividsolutions.jts.algorithm.LineIntersector;
                    -import com.vividsolutions.jts.util.Debug;
                    -
                    -/**
                    - * Processes possible intersections detected by a {@link Noder}.
                    - * The {@link SegmentIntersector} is passed to a {@link Noder}.
                    - * The {@link SegmentIntersector#processIntersections(SegmentString, int, SegmentString, int)} method is called whenever the {@link Noder}
                    - * detects that two SegmentStrings might intersect.
                    - * This class may be used either to find all intersections, or
                    - * to detect the presence of an intersection.  In the latter case,
                    - * Noders may choose to short-circuit their computation by calling the
                    - * {@link #isDone()} method.
                    - * This class is an example of the Strategy pattern.
                    - *
                    - * @version 1.7
                    - */
                    -public interface SegmentIntersector
                    -{
                    -  /**
                    -   * This method is called by clients
                    -   * of the {@link SegmentIntersector} interface to process
                    -   * intersections for two segments of the {@link SegmentString}s being intersected.
                    -   */
                    -  void processIntersections(
                    -    SegmentString e0,  int segIndex0,
                    -    SegmentString e1,  int segIndex1
                    -     );
                    -  
                    -  /**
                    -   * Reports whether the client of this class
                    -   * needs to continue testing all intersections in an arrangement.
                    -   * 
                    -   * @return true if there is no need to continue testing segments
                    -   */
                    -  boolean isDone();
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentNode.java b/src/main/java/com/vividsolutions/jts/noding/SegmentNode.java
                    deleted file mode 100644
                    index 0f06885a30..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentNode.java
                    +++ /dev/null
                    @@ -1,102 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import java.io.PrintStream;
                    -import com.vividsolutions.jts.geom.Coordinate;
                    -
                    -/**
                    - * Represents an intersection point between two {@link SegmentString}s.
                    - *
                    - * @version 1.7
                    - */
                    -public class SegmentNode
                    -    implements Comparable
                    -{
                    -  private final NodedSegmentString segString;
                    -  public final Coordinate coord;   // the point of intersection
                    -  public final int segmentIndex;   // the index of the containing line segment in the parent edge
                    -  private final int segmentOctant;
                    -  private final boolean isInterior;
                    -
                    -  public SegmentNode(NodedSegmentString segString, Coordinate coord, int segmentIndex, int segmentOctant) {
                    -    this.segString = segString;
                    -    this.coord = new Coordinate(coord);
                    -    this.segmentIndex = segmentIndex;
                    -    this.segmentOctant = segmentOctant;
                    -    isInterior = ! coord.equals2D(segString.getCoordinate(segmentIndex));
                    -  }
                    -
                    -  /**
                    -   * Gets the {@link Coordinate} giving the location of this node.
                    -   * 
                    -   * @return the coordinate of the node
                    -   */
                    -  public Coordinate getCoordinate() 
                    -  {
                    -    return coord;
                    -  }
                    -  
                    -  public boolean isInterior() { return isInterior; }
                    -
                    -  public boolean isEndPoint(int maxSegmentIndex)
                    -  {
                    -    if (segmentIndex == 0 && ! isInterior) return true;
                    -    if (segmentIndex == maxSegmentIndex) return true;
                    -    return false;
                    -  }
                    -
                    -  /**
                    -   * @return -1 this SegmentNode is located before the argument location;
                    -   * 0 this SegmentNode is at the argument location;
                    -   * 1 this SegmentNode is located after the argument location
                    -   */
                    -  public int compareTo(Object obj)
                    -  {
                    -    SegmentNode other = (SegmentNode) obj;
                    -
                    -    if (segmentIndex < other.segmentIndex) return -1;
                    -    if (segmentIndex > other.segmentIndex) return 1;
                    -
                    -    if (coord.equals2D(other.coord)) return 0;
                    -
                    -    return SegmentPointComparator.compare(segmentOctant, coord, other.coord);
                    -    //return segment.compareNodePosition(this, other);
                    -  }
                    -
                    -  public void print(PrintStream out)
                    -  {
                    -    out.print(coord);
                    -    out.print(" seg # = " + segmentIndex);
                    -  }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentNodeList.java b/src/main/java/com/vividsolutions/jts/noding/SegmentNodeList.java
                    deleted file mode 100644
                    index 6579c9d149..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentNodeList.java
                    +++ /dev/null
                    @@ -1,383 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import java.io.PrintStream;
                    -import java.util.*;
                    -
                    -import com.vividsolutions.jts.geom.*;
                    -import com.vividsolutions.jts.util.*;
                    -
                    -/**
                    - * A list of the {@link SegmentNode}s present along a noded {@link SegmentString}.
                    - *
                    - * @version 1.7
                    - */
                    -public class SegmentNodeList
                    -{
                    -  private Map nodeMap = new TreeMap();
                    -  private NodedSegmentString edge;  // the parent edge
                    -
                    -  public SegmentNodeList(NodedSegmentString edge)
                    -  {
                    -    this.edge = edge;
                    -  }
                    -
                    -  public NodedSegmentString getEdge() { return edge; }
                    -
                    -  /**
                    -   * Adds an intersection into the list, if it isn't already there.
                    -   * The input segmentIndex and dist are expected to be normalized.
                    -   *
                    -   * @return the SegmentIntersection found or added
                    -   */
                    -  public SegmentNode add(Coordinate intPt, int segmentIndex)
                    -  {
                    -    SegmentNode eiNew = new SegmentNode(edge, intPt, segmentIndex, edge.getSegmentOctant(segmentIndex));
                    -    SegmentNode ei = (SegmentNode) nodeMap.get(eiNew);
                    -    if (ei != null) {
                    -      // debugging sanity check
                    -      Assert.isTrue(ei.coord.equals2D(intPt), "Found equal nodes with different coordinates");
                    -//      if (! ei.coord.equals2D(intPt))
                    -//        Debug.println("Found equal nodes with different coordinates");
                    -
                    -      return ei;
                    -    }
                    -    // node does not exist, so create it
                    -    nodeMap.put(eiNew, eiNew);
                    -    return eiNew;
                    -  }
                    -
                    -  /**
                    -   * returns an iterator of SegmentNodes
                    -   */
                    -  public Iterator iterator() { return nodeMap.values().iterator(); }
                    -
                    -  /**
                    -   * Adds nodes for the first and last points of the edge
                    -   */
                    -  private void addEndpoints()
                    -  {
                    -    int maxSegIndex = edge.size() - 1;
                    -    add(edge.getCoordinate(0), 0);
                    -    add(edge.getCoordinate(maxSegIndex), maxSegIndex);
                    -  }
                    -
                    -  /**
                    -   * Adds nodes for any collapsed edge pairs.
                    -   * Collapsed edge pairs can be caused by inserted nodes, or they can be
                    -   * pre-existing in the edge vertex list.
                    -   * In order to provide the correct fully noded semantics,
                    -   * the vertex at the base of a collapsed pair must also be added as a node.
                    -   */
                    -  private void addCollapsedNodes()
                    -  {
                    -    List collapsedVertexIndexes = new ArrayList();
                    -
                    -    findCollapsesFromInsertedNodes(collapsedVertexIndexes);
                    -    findCollapsesFromExistingVertices(collapsedVertexIndexes);
                    -
                    -    // node the collapses
                    -    for (Iterator it = collapsedVertexIndexes.iterator(); it.hasNext(); ) {
                    -      int vertexIndex = ((Integer) it.next()).intValue();
                    -      add(edge.getCoordinate(vertexIndex), vertexIndex);
                    -    }
                    -  }
                    -
                    -  /**
                    -   * Adds nodes for any collapsed edge pairs
                    -   * which are pre-existing in the vertex list.
                    -   */
                    -  private void findCollapsesFromExistingVertices(List collapsedVertexIndexes)
                    -  {
                    -    for (int i = 0; i < edge.size() - 2; i++) {
                    -      Coordinate p0 = edge.getCoordinate(i);
                    -      Coordinate p1 = edge.getCoordinate(i + 1);
                    -      Coordinate p2 = edge.getCoordinate(i + 2);
                    -      if (p0.equals2D(p2)) {
                    -        // add base of collapse as node
                    -        collapsedVertexIndexes.add(new Integer(i + 1));
                    -      }
                    -    }
                    -  }
                    -
                    -  /**
                    -   * Adds nodes for any collapsed edge pairs caused by inserted nodes
                    -   * Collapsed edge pairs occur when the same coordinate is inserted as a node
                    -   * both before and after an existing edge vertex.
                    -   * To provide the correct fully noded semantics,
                    -   * the vertex must be added as a node as well.
                    -   */
                    -  private void findCollapsesFromInsertedNodes(List collapsedVertexIndexes)
                    -  {
                    -    int[] collapsedVertexIndex = new int[1];
                    -    Iterator it = iterator();
                    -    // there should always be at least two entries in the list, since the endpoints are nodes
                    -    SegmentNode eiPrev = (SegmentNode) it.next();
                    -    while (it.hasNext()) {
                    -      SegmentNode ei = (SegmentNode) it.next();
                    -      boolean isCollapsed = findCollapseIndex(eiPrev, ei, collapsedVertexIndex);
                    -      if (isCollapsed)
                    -        collapsedVertexIndexes.add(new Integer(collapsedVertexIndex[0]));
                    -
                    -      eiPrev = ei;
                    -    }
                    -  }
                    -
                    -  private boolean findCollapseIndex(SegmentNode ei0, SegmentNode ei1, int[] collapsedVertexIndex)
                    -  {
                    -    // only looking for equal nodes
                    -    if (! ei0.coord.equals2D(ei1.coord)) return false;
                    -
                    -    int numVerticesBetween = ei1.segmentIndex - ei0.segmentIndex;
                    -    if (! ei1.isInterior()) {
                    -      numVerticesBetween--;
                    -    }
                    -
                    -    // if there is a single vertex between the two equal nodes, this is a collapse
                    -    if (numVerticesBetween == 1) {
                    -      collapsedVertexIndex[0] = ei0.segmentIndex + 1;
                    -      return true;
                    -    }
                    -    return false;
                    -  }
                    -
                    -
                    -  /**
                    -   * Creates new edges for all the edges that the intersections in this
                    -   * list split the parent edge into.
                    -   * Adds the edges to the provided argument list
                    -   * (this is so a single list can be used to accumulate all split edges
                    -   * for a set of {@link SegmentString}s).
                    -   */
                    -  public void addSplitEdges(Collection edgeList)
                    -  {
                    -    // ensure that the list has entries for the first and last point of the edge
                    -    addEndpoints();
                    -    addCollapsedNodes();
                    -
                    -    Iterator it = iterator();
                    -    // there should always be at least two entries in the list, since the endpoints are nodes
                    -    SegmentNode eiPrev = (SegmentNode) it.next();
                    -    while (it.hasNext()) {
                    -      SegmentNode ei = (SegmentNode) it.next();
                    -      SegmentString newEdge = createSplitEdge(eiPrev, ei);
                    -      /*
                    -      if (newEdge.size() < 2)
                    -        throw new RuntimeException("created single point edge: " + newEdge.toString());
                    -      */
                    -      edgeList.add(newEdge);
                    -      eiPrev = ei;
                    -    }
                    -    //checkSplitEdgesCorrectness(testingSplitEdges);
                    -  }
                    -
                    -  /**
                    -   * Checks the correctness of the set of split edges corresponding to this edge.
                    -   *
                    -   * @param splitEdges the split edges for this edge (in order)
                    -   */
                    -  private void checkSplitEdgesCorrectness(List splitEdges)
                    -  {
                    -    Coordinate[] edgePts = edge.getCoordinates();
                    -
                    -    // check that first and last points of split edges are same as endpoints of edge
                    -    SegmentString split0 = (SegmentString) splitEdges.get(0);
                    -    Coordinate pt0 = split0.getCoordinate(0);
                    -    if (! pt0.equals2D(edgePts[0]))
                    -      throw new RuntimeException("bad split edge start point at " + pt0);
                    -
                    -    SegmentString splitn = (SegmentString) splitEdges.get(splitEdges.size() - 1);
                    -    Coordinate[] splitnPts = splitn.getCoordinates();
                    -    Coordinate ptn = splitnPts[splitnPts.length - 1];
                    -    if (! ptn.equals2D(edgePts[edgePts.length - 1]))
                    -      throw new RuntimeException("bad split edge end point at " + ptn);
                    -
                    -  }
                    -
                    -  /**
                    -   * Create a new "split edge" with the section of points between
                    -   * (and including) the two intersections.
                    -   * The label for the new edge is the same as the label for the parent edge.
                    -   */
                    -  SegmentString createSplitEdge(SegmentNode ei0, SegmentNode ei1)
                    -  {
                    -//Debug.println("\ncreateSplitEdge"); Debug.print(ei0); Debug.print(ei1);
                    -    int npts = ei1.segmentIndex - ei0.segmentIndex + 2;
                    -
                    -    Coordinate lastSegStartPt = edge.getCoordinate(ei1.segmentIndex);
                    -    // if the last intersection point is not equal to the its segment start pt,
                    -    // add it to the points list as well.
                    -    // (This check is needed because the distance metric is not totally reliable!)
                    -    // The check for point equality is 2D only - Z values are ignored
                    -    boolean useIntPt1 = ei1.isInterior() || ! ei1.coord.equals2D(lastSegStartPt);
                    -    if (! useIntPt1) {
                    -      npts--;
                    -    }
                    -
                    -    Coordinate[] pts = new Coordinate[npts];
                    -    int ipt = 0;
                    -    pts[ipt++] = new Coordinate(ei0.coord);
                    -    for (int i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) {
                    -      pts[ipt++] = edge.getCoordinate(i);
                    -    }
                    -    if (useIntPt1) pts[ipt] = new Coordinate(ei1.coord);
                    -
                    -    return new NodedSegmentString(pts, edge.getData());
                    -  }
                    -
                    -  /**
                    -   * Gets the list of coordinates for the fully noded segment string,
                    -   * including all original segment string vertices and vertices
                    -   * introduced by nodes in this list.
                    -   * Repeated coordinates are collapsed.
                    -   * 
                    -   * @return an array of Coordinates
                    -   * 
                    -   */
                    -  public Coordinate[] getSplitCoordinates()
                    -  {
                    -    CoordinateList coordList = new CoordinateList();
                    -    // ensure that the list has entries for the first and last point of the edge
                    -    addEndpoints();
                    -
                    -    Iterator it = iterator();
                    -    // there should always be at least two entries in the list, since the endpoints are nodes
                    -    SegmentNode eiPrev = (SegmentNode) it.next();
                    -    while (it.hasNext()) {
                    -      SegmentNode ei = (SegmentNode) it.next();
                    -      addEdgeCoordinates(eiPrev, ei, coordList);
                    -      eiPrev = ei;
                    -    }
                    -    return coordList.toCoordinateArray();
                    -  }
                    -
                    -  private void addEdgeCoordinates(SegmentNode ei0, SegmentNode ei1,
                    -      CoordinateList coordList) {
                    -    int npts = ei1.segmentIndex - ei0.segmentIndex + 2;
                    -
                    -    Coordinate lastSegStartPt = edge.getCoordinate(ei1.segmentIndex);
                    -    // if the last intersection point is not equal to the its segment start pt,
                    -    // add it to the points list as well.
                    -    // (This check is needed because the distance metric is not totally reliable!)
                    -    // The check for point equality is 2D only - Z values are ignored
                    -    boolean useIntPt1 = ei1.isInterior() || ! ei1.coord.equals2D(lastSegStartPt);
                    -    if (! useIntPt1) {
                    -      npts--;
                    -    }
                    -
                    -    int ipt = 0;
                    -    coordList.add(new Coordinate(ei0.coord), false);
                    -    for (int i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) {
                    -      coordList.add(edge.getCoordinate(i));
                    -    }
                    -    if (useIntPt1) {
                    -      coordList.add(new Coordinate(ei1.coord));
                    -    }
                    -  }
                    -
                    -  public void print(PrintStream out)
                    -  {
                    -    out.println("Intersections:");
                    -    for (Iterator it = iterator(); it.hasNext(); ) {
                    -      SegmentNode ei = (SegmentNode) it.next();
                    -      ei.print(out);
                    -    }
                    -  }
                    -}
                    -
                    -// INCOMPLETE!
                    -class NodeVertexIterator
                    -    implements Iterator
                    -{
                    -  private SegmentNodeList nodeList;
                    -  private NodedSegmentString edge;
                    -  private Iterator nodeIt;
                    -  private SegmentNode currNode = null;
                    -  private SegmentNode nextNode = null;
                    -  private int currSegIndex = 0;
                    -
                    -  NodeVertexIterator(SegmentNodeList nodeList)
                    -  {
                    -    this.nodeList = nodeList;
                    -    edge = nodeList.getEdge();
                    -    nodeIt = nodeList.iterator();
                    -    readNextNode();
                    -  }
                    -
                    -  public boolean hasNext() {
                    -    if (nextNode == null) return false;
                    -    return true;
                    -  }
                    -
                    -  public Object next()
                    -  {
                    -    if (currNode == null) {
                    -      currNode = nextNode;
                    -      currSegIndex = currNode.segmentIndex;
                    -      readNextNode();
                    -      return currNode;
                    -    }
                    -    // check for trying to read too far
                    -    if (nextNode == null) return null;
                    -
                    -    if (nextNode.segmentIndex == currNode.segmentIndex) {
                    -      currNode = nextNode;
                    -      currSegIndex = currNode.segmentIndex;
                    -      readNextNode();
                    -      return currNode;
                    -    }
                    -
                    -    if (nextNode.segmentIndex > currNode.segmentIndex) {
                    -
                    -    }
                    -    return null;
                    -  }
                    -
                    -  private void readNextNode()
                    -  {
                    -    if (nodeIt.hasNext())
                    -      nextNode = (SegmentNode) nodeIt.next();
                    -    else
                    -      nextNode = null;
                    -  }
                    -  /**
                    -   *  Not implemented.
                    -   *
                    -   *@throws  UnsupportedOperationException  This method is not implemented.
                    -   */
                    -  public void remove() {
                    -    throw new UnsupportedOperationException(getClass().getName());
                    -  }
                    -
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentPointComparator.java b/src/main/java/com/vividsolutions/jts/noding/SegmentPointComparator.java
                    deleted file mode 100644
                    index 192ea4f9d7..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentPointComparator.java
                    +++ /dev/null
                    @@ -1,98 +0,0 @@
                    -/*
                    -* The JTS Topology Suite is a collection of Java classes that
                    -* implement the fundamental operations required to validate a given
                    -* geo-spatial data set to a known topological specification.
                    -*
                    -* Copyright (C) 2001 Vivid Solutions
                    -*
                    -* This library is free software; you can redistribute it and/or
                    -* modify it under the terms of the GNU Lesser General Public
                    -* License as published by the Free Software Foundation; either
                    -* version 2.1 of the License, or (at your option) any later version.
                    -*
                    -* This library is distributed in the hope that it will be useful,
                    -* but WITHOUT ANY WARRANTY; without even the implied warranty of
                    -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    -* Lesser General Public License for more details.
                    -*
                    -* You should have received a copy of the GNU Lesser General Public
                    -* License along with this library; if not, write to the Free Software
                    -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    -*
                    -* For more information, contact:
                    -*
                    -*     Vivid Solutions
                    -*     Suite #1A
                    -*     2328 Government Street
                    -*     Victoria BC  V8T 5G5
                    -*     Canada
                    -*
                    -*     (250)385-6040
                    -*     www.vividsolutions.com
                    -*/
                    -
                    -package com.vividsolutions.jts.noding;
                    -
                    -import com.vividsolutions.jts.geom.Coordinate;
                    -import com.vividsolutions.jts.util.Assert;
                    -
                    -/**
                    - * Implements a robust method of comparing the relative position of two
                    - * points along the same segment.
                    - * The coordinates are assumed to lie "near" the segment.
                    - * This means that this algorithm will only return correct results
                    - * if the input coordinates
                    - * have the same precision and correspond to rounded values
                    - * of exact coordinates lying on the segment.
                    - *
                    - * @version 1.7
                    - */
                    -public class SegmentPointComparator {
                    -
                    -  /**
                    -   * Compares two {@link Coordinate}s for their relative position along a segment
                    -   * lying in the specified {@link Octant}.
                    -   *
                    -   * @return -1 node0 occurs first;
                    -   * 0 the two nodes are equal;
                    -   * 1 node1 occurs first
                    -   */
                    -  public static int compare(int octant, Coordinate p0, Coordinate p1)
                    -  {
                    -    // nodes can only be equal if their coordinates are equal
                    -    if (p0.equals2D(p1)) return 0;
                    -
                    -    int xSign = relativeSign(p0.x, p1.x);
                    -    int ySign = relativeSign(p0.y, p1.y);
                    -
                    -    switch (octant) {
                    -      case 0: return compareValue(xSign, ySign);
                    -      case 1: return compareValue(ySign, xSign);
                    -      case 2: return compareValue(ySign, -xSign);
                    -      case 3: return compareValue(-xSign, ySign);
                    -      case 4: return compareValue(-xSign, -ySign);
                    -      case 5: return compareValue(-ySign, -xSign);
                    -      case 6: return compareValue(-ySign, xSign);
                    -      case 7: return compareValue(xSign, -ySign);
                    -    }
                    -    Assert.shouldNeverReachHere("invalid octant value");
                    -    return 0;
                    -  }
                    -
                    -  public static int relativeSign(double x0, double x1)
                    -  {
                    -    if (x0 < x1) return -1;
                    -    if (x0 > x1) return 1;
                    -    return 0;
                    -  }
                    -
                    -  private static int compareValue(int compareSign0, int compareSign1)
                    -  {
                    -    if (compareSign0 < 0) return -1;
                    -    if (compareSign0 > 0) return 1;
                    -    if (compareSign1 < 0) return -1;
                    -    if (compareSign1 > 0) return 1;
                    -    return 0;
                    -
                    -  }
                    -}
                    diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentSetMutualIntersector.java b/src/main/java/com/vividsolutions/jts/noding/SegmentSetMutualIntersector.java
                    deleted file mode 100644
                    index e3f07a1eba..0000000000
                    --- a/src/main/java/com/vividsolutions/jts/noding/SegmentSetMutualIntersector.java
                    +++ /dev/null
                    @@ -1,70 +0,0 @@
                    -/*
                    - * The JTS Topology Suite is a collection of Java classes that
                    - * implement the fundamental operations required to validate a given
                    - * geo-spatial data set to a known topological specification.
                    - *
                    - * Copyright (C) 2001 Vivid Solutions
                    - *
                    - * This library is free software; you can redistribute it and/or
                    - * modify it under the terms of the GNU Lesser General Public
                    - * License as published by the Free Software Foundation; either
                    - * version 2.1 of the License, or (at your option) any later version.
                    - *
                    - * This library is distributed in the hope that it will be useful,
                    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
                    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                    - * Lesser General Public License for more details.
                    - *
                    - * You should have received a copy of the GNU Lesser General Public
                    - * License along with this library; if not, write to the Free Software
                    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    - *
                    - * For more information, contact:
                    - *
                    - *     Vivid Solutions
                    - *     Suite #1A
                    - *     2328 Government Street
                    - *     Victoria BC  V8T 5G5
                    - *     Canada
                    - *
                    - *     (250)385-6040
                    - *     www.vividsolutions.com
                    - */
                    -package com.vividsolutions.jts.noding;
                    -
                    -import java.util.*;
                    -
                    -/**
                    - * An intersector for the red-blue intersection problem.
                    - * In this class of line arrangement problem,
                    - * two disjoint sets of linestrings are intersected.
                    - * 

                    - * Implementing classes must provide a way - * of supplying the base set of segment strings to - * test against (e.g. in the constructor, - * for straightforward thread-safety). - *

                    - * In order to allow optimizing processing, - * the following condition is assumed to hold for each set: - *

                      - *
                    • the only intersection between any two linestrings occurs at their endpoints. - *
                    - * Implementations can take advantage of this fact to optimize processing - * (i.e by avoiding testing for intersections between linestrings - * belonging to the same set). - * - * @author Martin Davis - * @version 1.10 - */ -public interface SegmentSetMutualIntersector -{ - /** - * Computes the intersections with a given set of {@link SegmentString}s, - * using the supplied {@link SegmentIntersector}. - * - * @param segStrings a collection of {@link SegmentString}s to node - * @param segInt the intersection detector to either record intersection occurences - * or add intersection nodes to the input segment strings. - */ - void process(Collection segStrings, SegmentIntersector segInt); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentString.java b/src/main/java/com/vividsolutions/jts/noding/SegmentString.java deleted file mode 100644 index ca5439b722..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SegmentString.java +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * An interface for classes which represent a sequence of contiguous line segments. - * SegmentStrings can carry a context object, which is useful - * for preserving topological or parentage information. - * - * @version 1.7 - */ -public interface SegmentString -{ - /** - * Gets the user-defined data for this segment string. - * - * @return the user-defined data - */ - public Object getData(); - - /** - * Sets the user-defined data for this segment string. - * - * @param data an Object containing user-defined data - */ - public void setData(Object data); - - public int size(); - public Coordinate getCoordinate(int i); - public Coordinate[] getCoordinates(); - public boolean isClosed(); -} diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentStringDissolver.java b/src/main/java/com/vividsolutions/jts/noding/SegmentStringDissolver.java deleted file mode 100644 index 748ea45382..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SegmentStringDissolver.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Dissolves a noded collection of {@link SegmentString}s to produce - * a set of merged linework with unique segments. - * A custom {@link SegmentStringMerger} merging strategy - * can be supplied. - * This strategy will be called when two identical (up to orientation) - * strings are dissolved together. - * The default merging strategy is simply to discard one of the merged strings. - *

                    - * A common use for this class is to merge noded edges - * while preserving topological labelling. - * This requires a custom merging strategy to be supplied - * to merge the topology labels appropriately. - * - * @version 1.7 - * @see SegmentStringMerger - */ -public class SegmentStringDissolver -{ - /** - * A merging strategy which can be used to update the context data of {@link SegmentString}s - * which are merged during the dissolve process. - * - * @author mbdavis - * - */ - public interface SegmentStringMerger - { - /** - * Updates the context data of a SegmentString - * when an identical (up to orientation) one is found during dissolving. - * - * @param mergeTarget the segment string to update - * @param ssToMerge the segment string being dissolved - * @param isSameOrientation true if the strings are in the same direction, - * false if they are opposite - */ - void merge(SegmentString mergeTarget, SegmentString ssToMerge, boolean isSameOrientation); - } - - private SegmentStringMerger merger; - private Map ocaMap = new TreeMap(); - - // testing only - //private List testAddedSS = new ArrayList(); - - /** - * Creates a dissolver with a user-defined merge strategy. - * - * @param merger the merging strategy to use - */ - public SegmentStringDissolver(SegmentStringMerger merger) { - this.merger = merger; - } - - /** - * Creates a dissolver with the default merging strategy. - */ - public SegmentStringDissolver() { - this(null); - } - - /** - * Dissolve all {@link SegmentString}s in the input {@link Collection} - * @param segStrings - */ - public void dissolve(Collection segStrings) - { - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - dissolve((SegmentString) i.next()); - } - } - - private void add(OrientedCoordinateArray oca, SegmentString segString) - { - ocaMap.put(oca, segString); - //testAddedSS.add(oca); - } - - /** - * Dissolve the given {@link SegmentString}. - * - * @param segString the string to dissolve - */ - public void dissolve(SegmentString segString) - { - OrientedCoordinateArray oca = new OrientedCoordinateArray(segString.getCoordinates()); - SegmentString existing = findMatching(oca, segString); - if (existing == null) { - add(oca, segString); - } - else { - if (merger != null) { - boolean isSameOrientation - = CoordinateArrays.equals(existing.getCoordinates(), segString.getCoordinates()); - merger.merge(existing, segString, isSameOrientation); - } - } - } - - private SegmentString findMatching(OrientedCoordinateArray oca, - SegmentString segString) - { - SegmentString matchSS = (SegmentString) ocaMap.get(oca); - /* - boolean hasBeenAdded = checkAdded(oca); - if (matchSS == null && hasBeenAdded) { - System.out.println("added!"); - } - */ - return matchSS; - } - -/* - - private boolean checkAdded(OrientedCoordinateArray oca) - { - for (Iterator i = testAddedSS.iterator(); i.hasNext(); ) { - OrientedCoordinateArray addedOCA = (OrientedCoordinateArray) i.next(); - if (oca.compareTo(addedOCA) == 0) - return true; - } - return false; - } -*/ - - /** - * Gets the collection of dissolved (i.e. unique) {@link SegmentString}s - * - * @return the unique {@link SegmentString}s - */ - public Collection getDissolved() { return ocaMap.values(); } -} - - - diff --git a/src/main/java/com/vividsolutions/jts/noding/SegmentStringUtil.java b/src/main/java/com/vividsolutions/jts/noding/SegmentStringUtil.java deleted file mode 100644 index ef38ea58a9..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SegmentStringUtil.java +++ /dev/null @@ -1,120 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.MultiLineString; -import com.vividsolutions.jts.geom.util.LinearComponentExtracter; - -/** - * Utility methods for processing {@link SegmentString}s. - * - * @author Martin Davis - * - */ -public class SegmentStringUtil -{ - /** - * Extracts all linear components from a given {@link Geometry} - * to {@link SegmentString}s. - * The SegmentString data item is set to be the source Geometry. - * - * @param geom the geometry to extract from - * @return a List of SegmentStrings - */ - public static List extractSegmentStrings(Geometry geom) - { - return extractNodedSegmentStrings(geom); - } - - /** - * Extracts all linear components from a given {@link Geometry} - * to {@link SegmentString}s. - * The SegmentString data item is set to be the source Geometry. - * - * @param geom the geometry to extract from - * @return a List of SegmentStrings - */ - public static List extractNodedSegmentStrings(Geometry geom) - { - List segStr = new ArrayList(); - List lines = LinearComponentExtracter.getLines(geom); - for (Iterator i = lines.iterator(); i.hasNext(); ) { - LineString line = (LineString) i.next(); - Coordinate[] pts = line.getCoordinates(); - segStr.add(new NodedSegmentString(pts, geom)); - } - return segStr; - } - - /** - * Converts a collection of {@link SegmentString}s into a {@link Geometry}. - * The geometry will be either a {@link LineString} or a {@link MultiLineString} (possibly empty). - * - * @param segStrings a collection of SegmentStrings - * @return a LineString or MultiLineString - */ - public static Geometry toGeometry(Collection segStrings, GeometryFactory geomFact) - { - LineString[] lines = new LineString[segStrings.size()]; - int index = 0; - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString ss = (SegmentString) i.next(); - LineString line = geomFact.createLineString(ss.getCoordinates()); - lines[index++] = line; - } - if (lines.length == 1) return lines[0]; - return geomFact.createMultiLineString(lines); - } - - public static String toString(List segStrings) - { - StringBuffer buf = new StringBuffer(); - for (Iterator i = segStrings.iterator(); i.hasNext(); ) { - SegmentString segStr = (SegmentString) i.next(); - buf.append(segStr.toString()); - buf.append("\n"); - - } - return buf.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/SimpleNoder.java b/src/main/java/com/vividsolutions/jts/noding/SimpleNoder.java deleted file mode 100644 index 8c48f2b4d8..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SimpleNoder.java +++ /dev/null @@ -1,84 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Nodes a set of {@link SegmentString}s by - * performing a brute-force comparison of every segment to every other one. - * This has n^2 performance, so is too slow for use on large numbers - * of segments. - * - * @version 1.7 - */ -public class SimpleNoder - extends SinglePassNoder -{ - - private Collection nodedSegStrings; - - public SimpleNoder() { - } - - public Collection getNodedSubstrings() - { - return NodedSegmentString.getNodedSubstrings(nodedSegStrings); - } - - public void computeNodes(Collection inputSegStrings) - { - this.nodedSegStrings = inputSegStrings; - for (Iterator i0 = inputSegStrings.iterator(); i0.hasNext(); ) { - SegmentString edge0 = (SegmentString) i0.next(); - for (Iterator i1 = inputSegStrings.iterator(); i1.hasNext(); ) { - SegmentString edge1 = (SegmentString) i1.next(); - computeIntersects(edge0, edge1); - } - } - } - - private void computeIntersects(SegmentString e0, SegmentString e1) - { - Coordinate[] pts0 = e0.getCoordinates(); - Coordinate[] pts1 = e1.getCoordinates(); - for (int i0 = 0; i0 < pts0.length - 1; i0++) { - for (int i1 = 0; i1 < pts1.length - 1; i1++) { - segInt.processIntersections(e0, i0, e1, i1); - } - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java b/src/main/java/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java deleted file mode 100644 index 1c65d933cd..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; - -import com.vividsolutions.jts.geom.Coordinate; - - -/** - * Intersects two sets of {@link SegmentString}s using - * brute-force comparison. - * - * @version 1.7 - */ -public class SimpleSegmentSetMutualIntersector implements SegmentSetMutualIntersector -{ - private final Collection baseSegStrings; - - /** - * Constructs a new intersector for a given set of {@link SegmentStrings}. - * - * @param baseSegStrings the base segment strings to intersect - */ - public SimpleSegmentSetMutualIntersector(Collection segStrings) - { - this.baseSegStrings = segStrings; - } - - /** - * Calls {@link SegmentIntersector#processIntersections(SegmentString, int, SegmentString, int)} - * for all candidate intersections between - * the given collection of SegmentStrings and the set of base segments. - * - * @param a set of segments to intersect - * @param the segment intersector to use - */ - public void process(Collection segStrings, SegmentIntersector segInt) { - for (Iterator i = baseSegStrings.iterator(); i.hasNext(); ) { - SegmentString baseSS = (SegmentString) i.next(); - for (Iterator j = segStrings.iterator(); j.hasNext(); ) { - SegmentString ss = (SegmentString) j.next(); - intersect(baseSS, ss, segInt); - if (segInt.isDone()) - return; - } - } - } - - /** - * Processes all of the segment pairs in the given segment strings - * using the given SegmentIntersector. - * - * @param ss0 a Segment string - * @param ss1 a segment string - * @param segInt the segment intersector to use - */ - private void intersect(SegmentString ss0, SegmentString ss1, SegmentIntersector segInt) - { - Coordinate[] pts0 = ss0.getCoordinates(); - Coordinate[] pts1 = ss1.getCoordinates(); - for (int i0 = 0; i0 < pts0.length - 1; i0++) { - for (int i1 = 0; i1 < pts1.length - 1; i1++) { - segInt.processIntersections(ss0, i0, ss1, i1); - if (segInt.isDone()) - return; - } - } - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/SinglePassNoder.java b/src/main/java/com/vividsolutions/jts/noding/SinglePassNoder.java deleted file mode 100644 index d5fda7d886..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/SinglePassNoder.java +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding; - -import java.util.*; - -/** - * Base class for {@link Noder}s which make a single - * pass to find intersections. - * This allows using a custom {@link SegmentIntersector} - * (which for instance may simply identify intersections, rather than - * insert them). - * - * @version 1.7 - */ -public abstract class SinglePassNoder - implements Noder -{ - - protected SegmentIntersector segInt; - - public SinglePassNoder() { - } - - public SinglePassNoder(SegmentIntersector segInt) { - setSegmentIntersector(segInt); - } - - /** - * Sets the SegmentIntersector to use with this noder. - * A SegmentIntersector will normally add intersection nodes - * to the input segment strings, but it may not - it may - * simply record the presence of intersections. - * However, some Noders may require that intersections be added. - * - * @param segInt - */ - public void setSegmentIntersector(SegmentIntersector segInt) - { - this.segInt = segInt; - } - - /** - * Computes the noding for a collection of {@link SegmentString}s. - * Some Noders may add all these nodes to the input SegmentStrings; - * others may only add some or none at all. - * - * @param segStrings a collection of {@link SegmentString}s to node - */ - public abstract void computeNodes(Collection segStrings); - - /** - * Returns a {@link Collection} of fully noded {@link SegmentString}s. - * The SegmentStrings have the same context as their parent. - * - * @return a Collection of SegmentStrings - */ - public abstract Collection getNodedSubstrings(); - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/snapround/GeometryNoder.java b/src/main/java/com/vividsolutions/jts/noding/snapround/GeometryNoder.java deleted file mode 100644 index 779713d249..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/snapround/GeometryNoder.java +++ /dev/null @@ -1,145 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding.snapround; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.noding.snapround.*; - -/** - * Nodes the linework in a list of {@link Geometry}s using Snap-Rounding - * to a given {@link PrecisionModel}. - *

                    - * The input coordinates are expected to be rounded - * to the given precision model. - * This class does not perform that function. - * GeometryPrecisionReducer may be used to do this. - *

                    - * This class does not dissolve the output linework, - * so there may be duplicate linestrings in the output. - * Subsequent processing (e.g. polygonization) may require - * the linework to be unique. Using UnaryUnion is one way - * to do this (although this is an inefficient approach). - * - * - */ -public class GeometryNoder -{ - private GeometryFactory geomFact; - private PrecisionModel pm; - private boolean isValidityChecked = false; - - /** - * Creates a new noder which snap-rounds to a grid specified - * by the given {@link PrecisionModel}. - * - * @param pm the precision model for the grid to snap-round to - */ - public GeometryNoder(PrecisionModel pm) { - this.pm = pm; - } - - /** - * Sets whether noding validity is checked after noding is performed. - * - * @param isValidityChecked - */ - public void setValidate(boolean isValidityChecked) - { - this.isValidityChecked = isValidityChecked; - } - - /** - * Nodes the linework of a set of Geometrys using SnapRounding. - * - * @param geoms a Collection of Geometrys of any type - * @return a List of LineStrings representing the noded linework of the input - */ - public List node(Collection geoms) - { - // get geometry factory - Geometry geom0 = (Geometry) geoms.iterator().next(); - geomFact = geom0.getFactory(); - - List segStrings = toSegmentStrings(extractLines(geoms)); - //Noder sr = new SimpleSnapRounder(pm); - Noder sr = new MCIndexSnapRounder(pm); - sr.computeNodes(segStrings); - Collection nodedLines = sr.getNodedSubstrings(); - - //TODO: improve this to check for full snap-rounded correctness - if (isValidityChecked) { - NodingValidator nv = new NodingValidator(nodedLines); - nv.checkValid(); - } - - return toLineStrings(nodedLines); - } - - private List toLineStrings(Collection segStrings) - { - List lines = new ArrayList(); - for (Iterator it = segStrings.iterator(); it.hasNext(); ) { - SegmentString ss = (SegmentString) it.next(); - // skip collapsed lines - if (ss.size() < 2) - continue; - lines.add(geomFact.createLineString(ss.getCoordinates())); - } - return lines; - } - - private List extractLines(Collection geoms) - { - List lines = new ArrayList(); - LinearComponentExtracter lce = new LinearComponentExtracter(lines); - for (Iterator it = geoms.iterator(); it.hasNext(); ) { - Geometry geom = (Geometry) it.next(); - geom.apply(lce); - } - return lines; - } - - private List toSegmentStrings(Collection lines) - { - List segStrings = new ArrayList(); - for (Iterator it = lines.iterator(); it.hasNext(); ) { - LineString line = (LineString) it.next(); - segStrings.add(new NodedSegmentString(line.getCoordinates(), null)); - } - return segStrings; - } -} diff --git a/src/main/java/com/vividsolutions/jts/noding/snapround/HotPixel.java b/src/main/java/com/vividsolutions/jts/noding/snapround/HotPixel.java deleted file mode 100644 index dd2a6a9714..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/snapround/HotPixel.java +++ /dev/null @@ -1,321 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding.snapround; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.WKTWriter; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.util.*; - -/** - * Implements a "hot pixel" as used in the Snap Rounding algorithm. - * A hot pixel contains the interior of the tolerance square and - * the boundary - * minus the top and right segments. - *

                    - * The hot pixel operations are all computed in the integer domain - * to avoid rounding problems. - * - * @version 1.7 - */ -public class HotPixel -{ - // testing only -// public static int nTests = 0; - - private LineIntersector li; - - private Coordinate pt; - private Coordinate originalPt; - private Coordinate ptScaled; - - private Coordinate p0Scaled; - private Coordinate p1Scaled; - - private double scaleFactor; - - private double minx; - private double maxx; - private double miny; - private double maxy; - - /** - * The corners of the hot pixel, in the order: - * 10 - * 23 - */ - private Coordinate[] corner = new Coordinate[4]; - - private Envelope safeEnv = null; - - /** - * Creates a new hot pixel, using a given scale factor. - * The scale factor must be strictly positive (non-zero). - * - * @param pt the coordinate at the centre of the pixel - * @param scaleFactor the scaleFactor determining the pixel size. Must be > 0 - * @param li the intersector to use for testing intersection with line segments - * - */ - public HotPixel(Coordinate pt, double scaleFactor, LineIntersector li) { - originalPt = pt; - this.pt = pt; - this.scaleFactor = scaleFactor; - this.li = li; - //tolerance = 0.5; - if (scaleFactor <= 0) - throw new IllegalArgumentException("Scale factor must be non-zero"); - if (scaleFactor != 1.0) { - this.pt = new Coordinate(scale(pt.x), scale(pt.y)); - p0Scaled = new Coordinate(); - p1Scaled = new Coordinate(); - } - initCorners(this.pt); - } - - /** - * Gets the coordinate this hot pixel is based at. - * - * @return the coordinate of the pixel - */ - public Coordinate getCoordinate() { return originalPt; } - - private static final double SAFE_ENV_EXPANSION_FACTOR = 0.75; - - /** - * Returns a "safe" envelope that is guaranteed to contain the hot pixel. - * The envelope returned will be larger than the exact envelope of the - * pixel. - * - * @return an envelope which contains the hot pixel - */ - public Envelope getSafeEnvelope() - { - if (safeEnv == null) { - double safeTolerance = SAFE_ENV_EXPANSION_FACTOR / scaleFactor; - safeEnv = new Envelope(originalPt.x - safeTolerance, - originalPt.x + safeTolerance, - originalPt.y - safeTolerance, - originalPt.y + safeTolerance - ); - } - return safeEnv; - } - - private void initCorners(Coordinate pt) - { - double tolerance = 0.5; - minx = pt.x - tolerance; - maxx = pt.x + tolerance; - miny = pt.y - tolerance; - maxy = pt.y + tolerance; - - corner[0] = new Coordinate(maxx, maxy); - corner[1] = new Coordinate(minx, maxy); - corner[2] = new Coordinate(minx, miny); - corner[3] = new Coordinate(maxx, miny); - } - - private double scale(double val) - { - return (double) Math.round(val * scaleFactor); - } - - /** - * Tests whether the line segment (p0-p1) - * intersects this hot pixel. - * - * @param p0 the first coordinate of the line segment to test - * @param p1 the second coordinate of the line segment to test - * @return true if the line segment intersects this hot pixel - */ - public boolean intersects(Coordinate p0, Coordinate p1) - { - if (scaleFactor == 1.0) - return intersectsScaled(p0, p1); - - copyScaled(p0, p0Scaled); - copyScaled(p1, p1Scaled); - return intersectsScaled(p0Scaled, p1Scaled); - } - - private void copyScaled(Coordinate p, Coordinate pScaled) - { - pScaled.x = scale(p.x); - pScaled.y = scale(p.y); - } - - private boolean intersectsScaled(Coordinate p0, Coordinate p1) - { - double segMinx = Math.min(p0.x, p1.x); - double segMaxx = Math.max(p0.x, p1.x); - double segMiny = Math.min(p0.y, p1.y); - double segMaxy = Math.max(p0.y, p1.y); - - boolean isOutsidePixelEnv = maxx < segMinx - || minx > segMaxx - || maxy < segMiny - || miny > segMaxy; - if (isOutsidePixelEnv) - return false; - boolean intersects = intersectsToleranceSquare(p0, p1); -// boolean intersectsPixelClosure = intersectsPixelClosure(p0, p1); - -// if (intersectsPixel != intersects) { -// Debug.println("Found hot pixel intersection mismatch at " + pt); -// Debug.println("Test segment: " + p0 + " " + p1); -// } - -/* - if (scaleFactor != 1.0) { - boolean intersectsScaled = intersectsScaledTest(p0, p1); - if (intersectsScaled != intersects) { - intersectsScaledTest(p0, p1); -// Debug.println("Found hot pixel scaled intersection mismatch at " + pt); -// Debug.println("Test segment: " + p0 + " " + p1); - } - return intersectsScaled; - } -*/ - - Assert.isTrue(! (isOutsidePixelEnv && intersects), "Found bad envelope test"); -// if (isOutsideEnv && intersects) { -// Debug.println("Found bad envelope test"); -// } - - return intersects; - //return intersectsPixelClosure; - } - - /** - * Tests whether the segment p0-p1 intersects the hot pixel tolerance square. - * Because the tolerance square point set is partially open (along the - * top and right) the test needs to be more sophisticated than - * simply checking for any intersection. - * However, it can take advantage of the fact that the hot pixel edges - * do not lie on the coordinate grid. - * It is sufficient to check if any of the following occur: - *

                      - *
                    • a proper intersection between the segment and any hot pixel edge - *
                    • an intersection between the segment and both the left and bottom hot pixel edges - * (which detects the case where the segment intersects the bottom left hot pixel corner) - *
                    • an intersection between a segment endpoint and the hot pixel coordinate - *
                    - * - * @param p0 - * @param p1 - * @return - */ - private boolean intersectsToleranceSquare(Coordinate p0, Coordinate p1) - { - boolean intersectsLeft = false; - boolean intersectsBottom = false; - //System.out.println("Hot Pixel: " + WKTWriter.toLineString(corner)); - //System.out.println("Line: " + WKTWriter.toLineString(p0, p1)); - - li.computeIntersection(p0, p1, corner[0], corner[1]); - if (li.isProper()) return true; - - li.computeIntersection(p0, p1, corner[1], corner[2]); - if (li.isProper()) return true; - if (li.hasIntersection()) intersectsLeft = true; - - li.computeIntersection(p0, p1, corner[2], corner[3]); - if (li.isProper()) return true; - if (li.hasIntersection()) intersectsBottom = true; - - li.computeIntersection(p0, p1, corner[3], corner[0]); - if (li.isProper()) return true; - - if (intersectsLeft && intersectsBottom) return true; - - if (p0.equals(pt)) return true; - if (p1.equals(pt)) return true; - - return false; - } - /** - * Test whether the given segment intersects - * the closure of this hot pixel. - * This is NOT the test used in the standard snap-rounding - * algorithm, which uses the partially closed tolerance square - * instead. - * This routine is provided for testing purposes only. - * - * @param p0 the start point of a line segment - * @param p1 the end point of a line segment - * @return true if the segment intersects the closure of the pixel's tolerance square - */ - private boolean intersectsPixelClosure(Coordinate p0, Coordinate p1) - { - li.computeIntersection(p0, p1, corner[0], corner[1]); - if (li.hasIntersection()) return true; - li.computeIntersection(p0, p1, corner[1], corner[2]); - if (li.hasIntersection()) return true; - li.computeIntersection(p0, p1, corner[2], corner[3]); - if (li.hasIntersection()) return true; - li.computeIntersection(p0, p1, corner[3], corner[0]); - if (li.hasIntersection()) return true; - - return false; - } - - /** - * Adds a new node (equal to the snap pt) to the specified segment - * if the segment passes through the hot pixel - * - * @param segStr - * @param segIndex - * @return true if a node was added to the segment - */ - public boolean addSnappedNode( - NodedSegmentString segStr, - int segIndex - ) - { - Coordinate p0 = segStr.getCoordinate(segIndex); - Coordinate p1 = segStr.getCoordinate(segIndex + 1); - - if (intersects(p0, p1)) { - //System.out.println("snapped: " + snapPt); - //System.out.println("POINT (" + snapPt.x + " " + snapPt.y + ")"); - segStr.addIntersection(getCoordinate(), segIndex); - - return true; - } - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexPointSnapper.java b/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexPointSnapper.java deleted file mode 100644 index bd400a0bc8..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexPointSnapper.java +++ /dev/null @@ -1,134 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.noding.snapround; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.index.ItemVisitor; -import com.vividsolutions.jts.index.SpatialIndex; -import com.vividsolutions.jts.index.chain.MonotoneChain; -import com.vividsolutions.jts.index.chain.MonotoneChainSelectAction; -import com.vividsolutions.jts.index.strtree.STRtree; -import com.vividsolutions.jts.noding.NodedSegmentString; -import com.vividsolutions.jts.noding.SegmentString; - -/** - * "Snaps" all {@link SegmentString}s in a {@link SpatialIndex} containing - * {@link MonotoneChain}s to a given {@link HotPixel}. - * - * @version 1.7 - */ -public class MCIndexPointSnapper -{ - //public static final int nSnaps = 0; - - private STRtree index; - - public MCIndexPointSnapper(SpatialIndex index) { - this.index = (STRtree) index; - } - - /** - * Snaps (nodes) all interacting segments to this hot pixel. - * The hot pixel may represent a vertex of an edge, - * in which case this routine uses the optimization - * of not noding the vertex itself - * - * @param hotPixel the hot pixel to snap to - * @param parentEdge the edge containing the vertex, if applicable, or null - * @param hotPixelVertexIndex the index of the hotPixel vertex, if applicable, or -1 - * @return true if a node was added for this pixel - */ - public boolean snap(HotPixel hotPixel, SegmentString parentEdge, int hotPixelVertexIndex) - { - final Envelope pixelEnv = hotPixel.getSafeEnvelope(); - final HotPixelSnapAction hotPixelSnapAction = new HotPixelSnapAction(hotPixel, parentEdge, hotPixelVertexIndex); - - index.query(pixelEnv, new ItemVisitor() { - public void visitItem(Object item) { - MonotoneChain testChain = (MonotoneChain) item; - testChain.select(pixelEnv, hotPixelSnapAction); - } - } - ); - return hotPixelSnapAction.isNodeAdded(); - } - - public boolean snap(HotPixel hotPixel) - { - return snap(hotPixel, null, -1); - } - - public class HotPixelSnapAction - extends MonotoneChainSelectAction - { - private HotPixel hotPixel; - private SegmentString parentEdge; - // is -1 if hotPixel is not a vertex - private int hotPixelVertexIndex; - private boolean isNodeAdded = false; - - public HotPixelSnapAction(HotPixel hotPixel, SegmentString parentEdge, int hotPixelVertexIndex) - { - this.hotPixel = hotPixel; - this.parentEdge = parentEdge; - this.hotPixelVertexIndex = hotPixelVertexIndex; - } - - public boolean isNodeAdded() { return isNodeAdded; } - - public void select(MonotoneChain mc, int startIndex) - { - NodedSegmentString ss = (NodedSegmentString) mc.getContext(); - /** - * Check to avoid snapping a hotPixel vertex to the same vertex. - * This method is called for segments which intersects the - * hot pixel, - * so need to check if either end of the segment is equal to the hot pixel - * and if so, do not snap. - * - * Sep 22 2012 - MD - currently do need to snap to every vertex, - * since otherwise the testCollapse1 test in SnapRoundingTest fails. - */ - if (parentEdge != null) { - if (ss == parentEdge && - (startIndex == hotPixelVertexIndex - )) - return; - } - isNodeAdded = hotPixel.addSnappedNode(ss, startIndex); - } - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java b/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java deleted file mode 100644 index 00007e6dce..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java +++ /dev/null @@ -1,167 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding.snapround; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.noding.*; - -/** - * Uses Snap Rounding to compute a rounded, - * fully noded arrangement from a set of {@link SegmentString}s. - * Implements the Snap Rounding technique described in - * papers by Hobby, Guibas & Marimont, and Goodrich et al. - * Snap Rounding assumes that all vertices lie on a uniform grid; - * hence the precision model of the input must be fixed precision, - * and all the input vertices must be rounded to that precision. - *

                    - * This implementation uses a monotone chains and a spatial index to - * speed up the intersection tests. - *

                    - * This implementation appears to be fully robust using an integer precision model. - * It will function with non-integer precision models, but the - * results are not 100% guaranteed to be correctly noded. - * - * @version 1.7 - */ -public class MCIndexSnapRounder - implements Noder -{ - private final PrecisionModel pm; - private LineIntersector li; - private final double scaleFactor; - private MCIndexNoder noder; - private MCIndexPointSnapper pointSnapper; - private Collection nodedSegStrings; - - public MCIndexSnapRounder(PrecisionModel pm) { - this.pm = pm; - li = new RobustLineIntersector(); - li.setPrecisionModel(pm); - scaleFactor = pm.getScale(); - } - - public Collection getNodedSubstrings() - { - return NodedSegmentString.getNodedSubstrings(nodedSegStrings); - } - - public void computeNodes(Collection inputSegmentStrings) - { - this.nodedSegStrings = inputSegmentStrings; - noder = new MCIndexNoder(); - pointSnapper = new MCIndexPointSnapper(noder.getIndex()); - snapRound(inputSegmentStrings, li); - - // testing purposes only - remove in final version - //checkCorrectness(inputSegmentStrings); - } - - private void checkCorrectness(Collection inputSegmentStrings) - { - Collection resultSegStrings = NodedSegmentString.getNodedSubstrings(inputSegmentStrings); - NodingValidator nv = new NodingValidator(resultSegStrings); - try { - nv.checkValid(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - private void snapRound(Collection segStrings, LineIntersector li) - { - List intersections = findInteriorIntersections(segStrings, li); - computeIntersectionSnaps(intersections); - computeVertexSnaps(segStrings); - } - - /** - * Computes all interior intersections in the collection of {@link SegmentString}s, - * and returns their @link Coordinate}s. - * - * Does NOT node the segStrings. - * - * @return a list of Coordinates for the intersections - */ - private List findInteriorIntersections(Collection segStrings, LineIntersector li) - { - InteriorIntersectionFinderAdder intFinderAdder = new InteriorIntersectionFinderAdder(li); - noder.setSegmentIntersector(intFinderAdder); - noder.computeNodes(segStrings); - return intFinderAdder.getInteriorIntersections(); - } - - /** - * Snaps segments to nodes created by segment intersections. - */ - private void computeIntersectionSnaps(Collection snapPts) - { - for (Iterator it = snapPts.iterator(); it.hasNext(); ) { - Coordinate snapPt = (Coordinate) it.next(); - HotPixel hotPixel = new HotPixel(snapPt, scaleFactor, li); - pointSnapper.snap(hotPixel); - } - } - - /** - * Snaps segments to all vertices. - * - * @param edges the list of segment strings to snap together - */ - public void computeVertexSnaps(Collection edges) - { - for (Iterator i0 = edges.iterator(); i0.hasNext(); ) { - NodedSegmentString edge0 = (NodedSegmentString) i0.next(); - computeVertexSnaps(edge0); - } - } - - /** - * Snaps segments to the vertices of a Segment String. - */ - private void computeVertexSnaps(NodedSegmentString e) - { - Coordinate[] pts0 = e.getCoordinates(); - for (int i = 0; i < pts0.length ; i++) { - HotPixel hotPixel = new HotPixel(pts0[i], scaleFactor, li); - boolean isNodeAdded = pointSnapper.snap(hotPixel, e, i); - // if a node is created for a vertex, that vertex must be noded too - if (isNodeAdded) { - e.addIntersection(pts0[i], i); - } - } -} - -} diff --git a/src/main/java/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java b/src/main/java/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java deleted file mode 100644 index 17072abb4a..0000000000 --- a/src/main/java/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java +++ /dev/null @@ -1,195 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.noding.snapround; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.noding.*; - -/** - * Uses Snap Rounding to compute a rounded, - * fully noded arrangement from a set of {@link SegmentString}s. - * Implements the Snap Rounding technique described in - * the papers by Hobby, Guibas & Marimont, and Goodrich et al. - * Snap Rounding assumes that all vertices lie on a uniform grid; - * hence the precision model of the input must be fixed precision, - * and all the input vertices must be rounded to that precision. - *

                    - * This implementation uses simple iteration over the line segments. - * This is not the most efficient approach for large sets of segments. - *

                    - * This implementation appears to be fully robust using an integer precision model. - * It will function with non-integer precision models, but the - * results are not 100% guaranteed to be correctly noded. - * - * @version 1.7 - */ -public class SimpleSnapRounder - implements Noder -{ - private final PrecisionModel pm; - private LineIntersector li; - private final double scaleFactor; - private Collection nodedSegStrings; - - public SimpleSnapRounder(PrecisionModel pm) { - this.pm = pm; - li = new RobustLineIntersector(); - li.setPrecisionModel(pm); - scaleFactor = pm.getScale(); - } - - /** - * @return a Collection of NodedSegmentStrings representing the substrings - * - */ - public Collection getNodedSubstrings() - { - return NodedSegmentString.getNodedSubstrings(nodedSegStrings); - } - - /** - * @param inputSegmentStrings a Collection of NodedSegmentStrings - */ - public void computeNodes(Collection inputSegmentStrings) - { - this.nodedSegStrings = inputSegmentStrings; - snapRound(inputSegmentStrings, li); - - // testing purposes only - remove in final version - //checkCorrectness(inputSegmentStrings); - } - - private void checkCorrectness(Collection inputSegmentStrings) - { - Collection resultSegStrings = NodedSegmentString.getNodedSubstrings(inputSegmentStrings); - NodingValidator nv = new NodingValidator(resultSegStrings); - try { - nv.checkValid(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - private void snapRound(Collection segStrings, LineIntersector li) - { - List intersections = findInteriorIntersections(segStrings, li); - computeSnaps(segStrings, intersections); - computeVertexSnaps(segStrings); - } - - /** - * Computes all interior intersections in the collection of {@link SegmentString}s, - * and returns their {@link Coordinate}s. - * - * Does NOT node the segStrings. - * - * @return a list of Coordinates for the intersections - */ - private List findInteriorIntersections(Collection segStrings, LineIntersector li) - { - InteriorIntersectionFinderAdder intFinderAdder = new InteriorIntersectionFinderAdder(li); - SinglePassNoder noder = new MCIndexNoder(); - noder.setSegmentIntersector(intFinderAdder); - noder.computeNodes(segStrings); - return intFinderAdder.getInteriorIntersections(); - } - - - /** - * Computes nodes introduced as a result of snapping segments to snap points (hot pixels) - * @param li - */ - private void computeSnaps(Collection segStrings, Collection snapPts) - { - for (Iterator i0 = segStrings.iterator(); i0.hasNext(); ) { - NodedSegmentString ss = (NodedSegmentString) i0.next(); - computeSnaps(ss, snapPts); - } - } - - private void computeSnaps(NodedSegmentString ss, Collection snapPts) - { - for (Iterator it = snapPts.iterator(); it.hasNext(); ) { - Coordinate snapPt = (Coordinate) it.next(); - HotPixel hotPixel = new HotPixel(snapPt, scaleFactor, li); - for (int i = 0; i < ss.size() - 1; i++) { - hotPixel.addSnappedNode(ss, i); - } - } - } - - /** - * Computes nodes introduced as a result of - * snapping segments to vertices of other segments - * - * @param edges the list of segment strings to snap together - */ - public void computeVertexSnaps(Collection edges) - { - for (Iterator i0 = edges.iterator(); i0.hasNext(); ) { - NodedSegmentString edge0 = (NodedSegmentString) i0.next(); - for (Iterator i1 = edges.iterator(); i1.hasNext(); ) { - NodedSegmentString edge1 = (NodedSegmentString) i1.next(); - computeVertexSnaps(edge0, edge1); - } - } - } - - /** - * Performs a brute-force comparison of every segment in each {@link SegmentString}. - * This has n^2 performance. - */ - private void computeVertexSnaps(NodedSegmentString e0, NodedSegmentString e1) - { - Coordinate[] pts0 = e0.getCoordinates(); - Coordinate[] pts1 = e1.getCoordinates(); - for (int i0 = 0; i0 < pts0.length - 1; i0++) { - HotPixel hotPixel = new HotPixel(pts0[i0], scaleFactor, li); - for (int i1 = 0; i1 < pts1.length - 1; i1++) { - // don't snap a vertex to itself - if (e0 == e1) { - if (i0 == i1) continue; - } - //System.out.println("trying " + pts0[i0] + " against " + pts1[i1] + pts1[i1 + 1]); - boolean isNodeAdded = hotPixel.addSnappedNode(e1, i1); - // if a node is created for a vertex, that vertex must be noded too - if (isNodeAdded) { - e0.addIntersection(pts0[i0], i0); - } - } - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/BoundaryOp.java b/src/main/java/com/vividsolutions/jts/operation/BoundaryOp.java deleted file mode 100644 index d6c5b67a75..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/BoundaryOp.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation; - -import java.util.*; -import com.vividsolutions.jts.algorithm.BoundaryNodeRule; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.GeometryGraph; - -/** - * Computes the boundary of a {@link Geometry}. - * Allows specifying the {@link BoundaryNodeRule} to be used. - * This operation will always return a {@link Geometry} of the appropriate - * dimension for the boundary (even if the input geometry is empty). - * The boundary of zero-dimensional geometries (Points) is - * always the empty {@link GeometryCollection}. - * - * @author Martin Davis - * @version 1.7 - */ - -public class BoundaryOp -{ - public static Geometry getBoundary(Geometry g) - { - BoundaryOp bop = new BoundaryOp(g); - return bop.getBoundary(); - } - - public static Geometry getBoundary(Geometry g, BoundaryNodeRule bnRule) - { - BoundaryOp bop = new BoundaryOp(g, bnRule); - return bop.getBoundary(); - } - - private Geometry geom; - private GeometryFactory geomFact; - private BoundaryNodeRule bnRule; - - public BoundaryOp(Geometry geom) - { - this(geom, BoundaryNodeRule.MOD2_BOUNDARY_RULE); - } - - public BoundaryOp(Geometry geom, BoundaryNodeRule bnRule) - { - this.geom = geom; - geomFact = geom.getFactory(); - this.bnRule = bnRule; - } - - public Geometry getBoundary() - { - if (geom instanceof LineString) return boundaryLineString((LineString) geom); - if (geom instanceof MultiLineString) return boundaryMultiLineString((MultiLineString) geom); - return geom.getBoundary(); - } - - private MultiPoint getEmptyMultiPoint() - { - return geomFact.createMultiPoint((CoordinateSequence) null); - } - - private Geometry boundaryMultiLineString(MultiLineString mLine) - { - if (geom.isEmpty()) { - return getEmptyMultiPoint(); - } - - Coordinate[] bdyPts = computeBoundaryCoordinates(mLine); - - // return Point or MultiPoint - if (bdyPts.length == 1) { - return geomFact.createPoint(bdyPts[0]); - } - // this handles 0 points case as well - return geomFact.createMultiPoint(bdyPts); - } - -/* -// MD - superseded - private Coordinate[] computeBoundaryFromGeometryGraph(MultiLineString mLine) - { - GeometryGraph g = new GeometryGraph(0, mLine, bnRule); - Coordinate[] bdyPts = g.getBoundaryPoints(); - return bdyPts; - } -*/ - - private Map endpointMap; - - private Coordinate[] computeBoundaryCoordinates(MultiLineString mLine) - { - List bdyPts = new ArrayList(); - endpointMap = new TreeMap(); - for (int i = 0; i < mLine.getNumGeometries(); i++) { - LineString line = (LineString) mLine.getGeometryN(i); - if (line.getNumPoints() == 0) - continue; - addEndpoint(line.getCoordinateN(0)); - addEndpoint(line.getCoordinateN(line.getNumPoints() - 1)); - } - - for (Iterator it = endpointMap.entrySet().iterator(); it.hasNext(); ) { - Map.Entry entry = (Map.Entry) it.next(); - Counter counter = (Counter) entry.getValue(); - int valence = counter.count; - if (bnRule.isInBoundary(valence)) { - bdyPts.add(entry.getKey()); - } - } - - return CoordinateArrays.toCoordinateArray(bdyPts); - } - - private void addEndpoint(Coordinate pt) - { - Counter counter = (Counter) endpointMap.get(pt); - if (counter == null) { - counter = new Counter(); - endpointMap.put(pt, counter); - } - counter.count++; - } - - private Geometry boundaryLineString(LineString line) - { - if (geom.isEmpty()) { - return getEmptyMultiPoint(); - } - - if (line.isClosed()) { - // check whether endpoints of valence 2 are on the boundary or not - boolean closedEndpointOnBoundary = bnRule.isInBoundary(2); - if (closedEndpointOnBoundary) { - return line.getStartPoint(); - } - else { - return geomFact.createMultiPoint((Coordinate[]) null); - } - } - return geomFact.createMultiPoint(new Point[]{ - line.getStartPoint(), - line.getEndPoint() - }); - } -} - -/** - * Stores an integer count, for use as a Map entry. - * - * @author Martin Davis - * @version 1.7 - */ -class Counter -{ - /** - * The value of the count - */ - int count; -} diff --git a/src/main/java/com/vividsolutions/jts/operation/GeometryGraphOperation.java b/src/main/java/com/vividsolutions/jts/operation/GeometryGraphOperation.java deleted file mode 100644 index 2bc62c61e3..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/GeometryGraphOperation.java +++ /dev/null @@ -1,91 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.GeometryGraph; - -/** - * The base class for operations that require {@link GeometryGraph}s. - * - * @version 1.7 - */ -public class GeometryGraphOperation -{ - protected final LineIntersector li = new RobustLineIntersector(); - protected PrecisionModel resultPrecisionModel; - - /** - * The operation args into an array so they can be accessed by index - */ - protected GeometryGraph[] arg; // the arg(s) of the operation - - public GeometryGraphOperation(Geometry g0, Geometry g1) - { - this(g0, g1, - BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE -// BoundaryNodeRule.ENDPOINT_BOUNDARY_RULE - ); - } - - public GeometryGraphOperation(Geometry g0, Geometry g1, BoundaryNodeRule boundaryNodeRule) - { - // use the most precise model for the result - if (g0.getPrecisionModel().compareTo(g1.getPrecisionModel()) >= 0) - setComputationPrecision(g0.getPrecisionModel()); - else - setComputationPrecision(g1.getPrecisionModel()); - - arg = new GeometryGraph[2]; - arg[0] = new GeometryGraph(0, g0, boundaryNodeRule); - arg[1] = new GeometryGraph(1, g1, boundaryNodeRule); - } - - public GeometryGraphOperation(Geometry g0) { - setComputationPrecision(g0.getPrecisionModel()); - - arg = new GeometryGraph[1]; - arg[0] = new GeometryGraph(0, g0);; - } - - public Geometry getArgGeometry(int i) { return arg[i].getGeometry(); } - - protected void setComputationPrecision(PrecisionModel pm) - { - resultPrecisionModel = pm; - li.setPrecisionModel(resultPrecisionModel); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/IsSimpleOp.java b/src/main/java/com/vividsolutions/jts/operation/IsSimpleOp.java deleted file mode 100644 index 2056a26a48..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/IsSimpleOp.java +++ /dev/null @@ -1,347 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.LinearComponentExtracter; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.index.SegmentIntersector; - -/** - * Tests whether a Geometry is simple. - * In general, the SFS specification of simplicity - * follows the rule: - *

                      - *
                    • A Geometry is simple if and only if the only self-intersections are at - * boundary points. - *
                    - *

                    - * Simplicity is defined for each {@link Geometry} type as follows: - *

                      - *
                    • Polygonal geometries are simple by definition, so - * isSimple trivially returns true. - * (Note: this means that isSimple cannot be used to test - * for (invalid) self-intersections in Polygons. - * In order to check if a Polygonal geometry has self-intersections, - * use {@link Geometry#isValid()}). - *
                    • Linear geometries are simple iff they do not self-intersect at interior points - * (i.e. points other than boundary points). - * This is equivalent to saying that no two linear components satisfy the SFS {@link Geometry#touches(Geometry)} - * predicate. - *
                    • Zero-dimensional (point) geometries are simple if and only if they have no - * repeated points. - *
                    • Empty geometries are always simple, by definition - *
                    - * For {@link Lineal} geometries the evaluation of simplicity - * can be customized by supplying a {@link BoundaryNodeRule} - * to define how boundary points are determined. - * The default is the SFS-standard {@link BoundaryNodeRule#MOD2_BOUNDARY_RULE}. - * Note that under the Mod-2 rule, closed LineStrings (rings) - * will never satisfy the touches predicate at their endpoints, since these are - * interior points, not boundary points. - * If it is required to test whether a set of LineStrings touch - * only at their endpoints, use IsSimpleOp with {@link BoundaryNodeRule#ENDPOINT_BOUNDARY_RULE}. - * For example, this can be used to validate that a set of lines form a topologically valid - * linear network. - * - * @see BoundaryNodeRule - * - * @version 1.7 - */ -public class IsSimpleOp -{ - private Geometry inputGeom; - private boolean isClosedEndpointsInInterior = true; - private Coordinate nonSimpleLocation = null; - - /** - * Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule - * - * @deprecated use IsSimpleOp(Geometry) - */ - public IsSimpleOp() { - } - - /** - * Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule - * - * @param geom the geometry to test - */ - public IsSimpleOp(Geometry geom) { - this.inputGeom = geom; - } - - /** - * Creates a simplicity checker using a given {@link BoundaryNodeRule} - * - * @param geom the geometry to test - * @param boundaryNodeRule the rule to use. - */ - public IsSimpleOp(Geometry geom, BoundaryNodeRule boundaryNodeRule) - { - this.inputGeom = geom; - isClosedEndpointsInInterior = ! boundaryNodeRule.isInBoundary(2); - } - - /** - * Tests whether the geometry is simple. - * - * @return true if the geometry is simple - */ - public boolean isSimple() - { - nonSimpleLocation = null; - return computeSimple(inputGeom); - } - - private boolean computeSimple(Geometry geom) - { - nonSimpleLocation = null; - if (geom.isEmpty()) return true; - if (geom instanceof LineString) return isSimpleLinearGeometry(geom); - if (geom instanceof MultiLineString) return isSimpleLinearGeometry(geom); - if (geom instanceof MultiPoint) return isSimpleMultiPoint((MultiPoint) geom); - if (geom instanceof Polygonal) return isSimplePolygonal(geom); - if (geom instanceof GeometryCollection) return isSimpleGeometryCollection(geom); - // all other geometry types are simple by definition - return true; - } - - /** - * Gets a coordinate for the location where the geometry - * fails to be simple. - * (i.e. where it has a non-boundary self-intersection). - * {@link #isSimple} must be called before this method is called. - * - * @return a coordinate for the location of the non-boundary self-intersection - * or null if the geometry is simple - */ - public Coordinate getNonSimpleLocation() - { - return nonSimpleLocation; - } - - /** - * Reports whether a {@link LineString} is simple. - * - * @param geom the lineal geometry to test - * @return true if the geometry is simple - * @deprecated use isSimple() - */ - public boolean isSimple(LineString geom) - { - return isSimpleLinearGeometry(geom); - } - - /** - * Reports whether a {@link MultiLineString} geometry is simple. - * - * @param geom the lineal geometry to test - * @return true if the geometry is simple - * @deprecated use isSimple() - */ - public boolean isSimple(MultiLineString geom) - { - return isSimpleLinearGeometry(geom); - } - - /** - * A MultiPoint is simple iff it has no repeated points - * @deprecated use isSimple() - */ - public boolean isSimple(MultiPoint mp) - { - return isSimpleMultiPoint(mp); - } - - private boolean isSimpleMultiPoint(MultiPoint mp) - { - if (mp.isEmpty()) return true; - Set points = new TreeSet(); - for (int i = 0; i < mp.getNumGeometries(); i++) { - Point pt = (Point) mp.getGeometryN(i); - Coordinate p = pt.getCoordinate(); - if (points.contains(p)) { - nonSimpleLocation = p; - return false; - } - points.add(p); - } - return true; - } - - /** - * Computes simplicity for polygonal geometries. - * Polygonal geometries are simple if and only if - * all of their component rings are simple. - * - * @param geom a Polygonal geometry - * @return true if the geometry is simple - */ - private boolean isSimplePolygonal(Geometry geom) - { - List rings = LinearComponentExtracter.getLines(geom); - for (Iterator i = rings.iterator(); i.hasNext(); ) { - LinearRing ring = (LinearRing) i.next(); - if (! isSimpleLinearGeometry(ring)) - return false; - } - return true; - } - - /** - * Semantics for GeometryCollection is - * simple iff all components are simple. - * - * @param geom - * @return true if the geometry is simple - */ - private boolean isSimpleGeometryCollection(Geometry geom) - { - for (int i = 0; i < geom.getNumGeometries(); i++ ) { - Geometry comp = geom.getGeometryN(i); - if (! computeSimple(comp)) - return false; - } - return true; - } - - private boolean isSimpleLinearGeometry(Geometry geom) - { - if (geom.isEmpty()) return true; - GeometryGraph graph = new GeometryGraph(0, geom); - LineIntersector li = new RobustLineIntersector(); - SegmentIntersector si = graph.computeSelfNodes(li, true); - // if no self-intersection, must be simple - if (! si.hasIntersection()) return true; - if (si.hasProperIntersection()) { - nonSimpleLocation = si.getProperIntersectionPoint(); - return false; - } - if (hasNonEndpointIntersection(graph)) return false; - if (isClosedEndpointsInInterior) { - if (hasClosedEndpointIntersection(graph)) return false; - } - return true; - } - - /** - * For all edges, check if there are any intersections which are NOT at an endpoint. - * The Geometry is not simple if there are intersections not at endpoints. - */ - private boolean hasNonEndpointIntersection(GeometryGraph graph) - { - for (Iterator i = graph.getEdgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - int maxSegmentIndex = e.getMaximumSegmentIndex(); - for (Iterator eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) eiIt.next(); - if (! ei.isEndPoint(maxSegmentIndex)) { - nonSimpleLocation = ei.getCoordinate(); - return true; - } - } - } - return false; - } - - private static class EndpointInfo { - Coordinate pt; - boolean isClosed; - int degree; - - public EndpointInfo(Coordinate pt) - { - this.pt = pt; - isClosed = false; - degree = 0; - } - - public Coordinate getCoordinate() { return pt; } - - public void addEndpoint(boolean isClosed) - { - degree++; - this.isClosed |= isClosed; - } - } - - /** - * Tests that no edge intersection is the endpoint of a closed line. - * This ensures that closed lines are not touched at their endpoint, - * which is an interior point according to the Mod-2 rule - * To check this we compute the degree of each endpoint. - * The degree of endpoints of closed lines - * must be exactly 2. - */ - private boolean hasClosedEndpointIntersection(GeometryGraph graph) - { - Map endPoints = new TreeMap(); - for (Iterator i = graph.getEdgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - int maxSegmentIndex = e.getMaximumSegmentIndex(); - boolean isClosed = e.isClosed(); - Coordinate p0 = e.getCoordinate(0); - addEndpoint(endPoints, p0, isClosed); - Coordinate p1 = e.getCoordinate(e.getNumPoints() - 1); - addEndpoint(endPoints, p1, isClosed); - } - - for (Iterator i = endPoints.values().iterator(); i.hasNext(); ) { - EndpointInfo eiInfo = (EndpointInfo) i.next(); - if (eiInfo.isClosed && eiInfo.degree != 2) { - nonSimpleLocation = eiInfo.getCoordinate(); - return true; - } - } - return false; - } - - /** - * Add an endpoint to the map, creating an entry for it if none exists - */ - private void addEndpoint(Map endPoints, Coordinate p, boolean isClosed) - { - EndpointInfo eiInfo = (EndpointInfo) endPoints.get(p); - if (eiInfo == null) { - eiInfo = new EndpointInfo(p); - endPoints.put(p, eiInfo); - } - eiInfo.addEndpoint(isClosed); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferBuilder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/BufferBuilder.java deleted file mode 100644 index cfa7427bd0..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferBuilder.java +++ /dev/null @@ -1,328 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * @version 1.7 - */ - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.operation.overlay.*; -import com.vividsolutions.jts.noding.*; - -import com.vividsolutions.jts.io.*; -import com.vividsolutions.jts.util.*; - - -/** - * Builds the buffer geometry for a given input geometry and precision model. - * Allows setting the level of approximation for circular arcs, - * and the precision model in which to carry out the computation. - *

                    - * When computing buffers in floating point double-precision - * it can happen that the process of iterated noding can fail to converge (terminate). - * In this case a {@link TopologyException} will be thrown. - * Retrying the computation in a fixed precision - * can produce more robust results. - * - * @version 1.7 - */ -class BufferBuilder -{ - /** - * Compute the change in depth as an edge is crossed from R to L - */ - private static int depthDelta(Label label) - { - int lLoc = label.getLocation(0, Position.LEFT); - int rLoc = label.getLocation(0, Position.RIGHT); - if (lLoc == Location.INTERIOR && rLoc == Location.EXTERIOR) - return 1; - else if (lLoc == Location.EXTERIOR && rLoc == Location.INTERIOR) - return -1; - return 0; - } - - private BufferParameters bufParams; - - private PrecisionModel workingPrecisionModel; - private Noder workingNoder; - private GeometryFactory geomFact; - private PlanarGraph graph; - private EdgeList edgeList = new EdgeList(); - - /** - * Creates a new BufferBuilder - */ - public BufferBuilder(BufferParameters bufParams) - { - this.bufParams = bufParams; - } - - /** - * Sets the precision model to use during the curve computation and noding, - * if it is different to the precision model of the Geometry. - * If the precision model is less than the precision of the Geometry precision model, - * the Geometry must have previously been rounded to that precision. - * - * @param pm the precision model to use - */ - public void setWorkingPrecisionModel(PrecisionModel pm) - { - workingPrecisionModel = pm; - } - - /** - * Sets the {@link Noder} to use during noding. - * This allows choosing fast but non-robust noding, or slower - * but robust noding. - * - * @param noder the noder to use - */ - public void setNoder(Noder noder) { workingNoder = noder; } - - - public Geometry buffer(Geometry g, double distance) - { - PrecisionModel precisionModel = workingPrecisionModel; - if (precisionModel == null) - precisionModel = g.getPrecisionModel(); - - // factory must be the same as the one used by the input - geomFact = g.getFactory(); - - OffsetCurveBuilder curveBuilder = new OffsetCurveBuilder(precisionModel, bufParams); - - OffsetCurveSetBuilder curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder); - - List bufferSegStrList = curveSetBuilder.getCurves(); - - // short-circuit test - if (bufferSegStrList.size() <= 0) { - return createEmptyResultGeometry(); - } - -//BufferDebug.runCount++; -//String filename = "run" + BufferDebug.runCount + "_curves"; -//System.out.println("saving " + filename); -//BufferDebug.saveEdges(bufferEdgeList, filename); -// DEBUGGING ONLY -//WKTWriter wktWriter = new WKTWriter(); -//Debug.println("Rings: " + wktWriter.write(convertSegStrings(bufferSegStrList.iterator()))); -//wktWriter.setMaxCoordinatesPerLine(10); -//System.out.println(wktWriter.writeFormatted(convertSegStrings(bufferSegStrList.iterator()))); - - computeNodedEdges(bufferSegStrList, precisionModel); - graph = new PlanarGraph(new OverlayNodeFactory()); - graph.addEdges(edgeList.getEdges()); - - List subgraphList = createSubgraphs(graph); - PolygonBuilder polyBuilder = new PolygonBuilder(geomFact); - buildSubgraphs(subgraphList, polyBuilder); - List resultPolyList = polyBuilder.getPolygons(); - - // just in case... - if (resultPolyList.size() <= 0) { - return createEmptyResultGeometry(); - } - - Geometry resultGeom = geomFact.buildGeometry(resultPolyList); - return resultGeom; - } - - private Noder getNoder(PrecisionModel precisionModel) - { - if (workingNoder != null) return workingNoder; - - // otherwise use a fast (but non-robust) noder - MCIndexNoder noder = new MCIndexNoder(); - LineIntersector li = new RobustLineIntersector(); - li.setPrecisionModel(precisionModel); - noder.setSegmentIntersector(new IntersectionAdder(li)); -// Noder noder = new IteratedNoder(precisionModel); - return noder; -// Noder noder = new SimpleSnapRounder(precisionModel); -// Noder noder = new MCIndexSnapRounder(precisionModel); -// Noder noder = new ScaledNoder(new MCIndexSnapRounder(new PrecisionModel(1.0)), -// precisionModel.getScale()); - } - - private void computeNodedEdges(List bufferSegStrList, PrecisionModel precisionModel) - { - Noder noder = getNoder(precisionModel); - noder.computeNodes(bufferSegStrList); - Collection nodedSegStrings = noder.getNodedSubstrings(); -// DEBUGGING ONLY -//BufferDebug.saveEdges(nodedEdges, "run" + BufferDebug.runCount + "_nodedEdges"); - - for (Iterator i = nodedSegStrings.iterator(); i.hasNext(); ) { - SegmentString segStr = (SegmentString) i.next(); - - /** - * Discard edges which have zero length, - * since they carry no information and cause problems with topology building - */ - Coordinate[] pts = segStr.getCoordinates(); - if (pts.length == 2 && pts[0].equals2D(pts[1])) - continue; - - Label oldLabel = (Label) segStr.getData(); - Edge edge = new Edge(segStr.getCoordinates(), new Label(oldLabel)); - insertUniqueEdge(edge); - } - //saveEdges(edgeList.getEdges(), "run" + runCount + "_collapsedEdges"); - } - - - /** - * Inserted edges are checked to see if an identical edge already exists. - * If so, the edge is not inserted, but its label is merged - * with the existing edge. - */ - protected void insertUniqueEdge(Edge e) - { -// MD 8 Oct 03 speed up identical edge lookup - // fast lookup - Edge existingEdge = edgeList.findEqualEdge(e); - - // If an identical edge already exists, simply update its label - if (existingEdge != null) { - Label existingLabel = existingEdge.getLabel(); - - Label labelToMerge = e.getLabel(); - // check if new edge is in reverse direction to existing edge - // if so, must flip the label before merging it - if (! existingEdge.isPointwiseEqual(e)) { - labelToMerge = new Label(e.getLabel()); - labelToMerge.flip(); - } - existingLabel.merge(labelToMerge); - - // compute new depth delta of sum of edges - int mergeDelta = depthDelta(labelToMerge); - int existingDelta = existingEdge.getDepthDelta(); - int newDelta = existingDelta + mergeDelta; - existingEdge.setDepthDelta(newDelta); - } - else { // no matching existing edge was found - // add this new edge to the list of edges in this graph - //e.setName(name + edges.size()); - edgeList.add(e); - e.setDepthDelta(depthDelta(e.getLabel())); - } - } - - private List createSubgraphs(PlanarGraph graph) - { - List subgraphList = new ArrayList(); - for (Iterator i = graph.getNodes().iterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (! node.isVisited()) { - BufferSubgraph subgraph = new BufferSubgraph(); - subgraph.create(node); - subgraphList.add(subgraph); - } - } - /** - * Sort the subgraphs in descending order of their rightmost coordinate. - * This ensures that when the Polygons for the subgraphs are built, - * subgraphs for shells will have been built before the subgraphs for - * any holes they contain. - */ - Collections.sort(subgraphList, Collections.reverseOrder()); - return subgraphList; - } - - /** - * Completes the building of the input subgraphs by depth-labelling them, - * and adds them to the PolygonBuilder. - * The subgraph list must be sorted in rightmost-coordinate order. - * - * @param subgraphList the subgraphs to build - * @param polyBuilder the PolygonBuilder which will build the final polygons - */ - private void buildSubgraphs(List subgraphList, PolygonBuilder polyBuilder) - { - List processedGraphs = new ArrayList(); - for (Iterator i = subgraphList.iterator(); i.hasNext(); ) { - BufferSubgraph subgraph = (BufferSubgraph) i.next(); - Coordinate p = subgraph.getRightmostCoordinate(); -// int outsideDepth = 0; -// if (polyBuilder.containsPoint(p)) -// outsideDepth = 1; - SubgraphDepthLocater locater = new SubgraphDepthLocater(processedGraphs); - int outsideDepth = locater.getDepth(p); -// try { - subgraph.computeDepth(outsideDepth); -// } -// catch (RuntimeException ex) { -// // debugging only -// //subgraph.saveDirEdges(); -// throw ex; -// } - subgraph.findResultEdges(); - processedGraphs.add(subgraph); - polyBuilder.add(subgraph.getDirectedEdges(), subgraph.getNodes()); - } - } - - private static Geometry convertSegStrings(Iterator it) - { - GeometryFactory fact = new GeometryFactory(); - List lines = new ArrayList(); - while (it.hasNext()) { - SegmentString ss = (SegmentString) it.next(); - LineString line = fact.createLineString(ss.getCoordinates()); - lines.add(line); - } - return fact.buildGeometry(lines); - } - - /** - * Gets the standard result for an empty buffer. - * Since buffer always returns a polygonal result, - * this is chosen to be an empty polygon. - * - * @return the empty result geometry - */ - private Geometry createEmptyResultGeometry() - { - Geometry emptyGeom = geomFact.createPolygon(null, null); - return emptyGeom; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java b/src/main/java/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java deleted file mode 100644 index a758bddea1..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.*; - -/** - * Simplifies a buffer input line to - * remove concavities with shallow depth. - *

                    - * The most important benefit of doing this - * is to reduce the number of points and the complexity of - * shape which will be buffered. - * It also reduces the risk of gores created by - * the quantized fillet arcs (although this issue - * should be eliminated in any case by the - * offset curve generation logic). - *

                    - * A key aspect of the simplification is that it - * affects inside (concave or inward) corners only. - * Convex (outward) corners are preserved, since they - * are required to ensure that the generated buffer curve - * lies at the correct distance from the input geometry. - *

                    - * Another important heuristic used is that the end segments - * of the input are never simplified. This ensures that - * the client buffer code is able to generate end caps faithfully. - *

                    - * No attempt is made to avoid self-intersections in the output. - * This is acceptable for use for generating a buffer offset curve, - * since the buffer algorithm is insensitive to invalid polygonal - * geometry. However, - * this means that this algorithm - * cannot be used as a general-purpose polygon simplification technique. - * - * @author Martin Davis - * - */ -public class BufferInputLineSimplifier -{ - /** - * Simplify the input coordinate list. - * If the distance tolerance is positive, - * concavities on the LEFT side of the line are simplified. - * If the supplied distance tolerance is negative, - * concavities on the RIGHT side of the line are simplified. - * - * @param inputLine the coordinate list to simplify - * @param distanceTol simplification distance tolerance to use - * @return the simplified coordinate list - */ - public static Coordinate[] simplify(Coordinate[] inputLine, double distanceTol) - { - BufferInputLineSimplifier simp = new BufferInputLineSimplifier(inputLine); - return simp.simplify(distanceTol); - } - - private static final int INIT = 0; - private static final int DELETE = 1; - private static final int KEEP = 1; - - - private Coordinate[] inputLine; - private double distanceTol; - private byte[] isDeleted; - private int angleOrientation = CGAlgorithms.COUNTERCLOCKWISE; - - public BufferInputLineSimplifier(Coordinate[] inputLine) { - this.inputLine = inputLine; - } - - /** - * Simplify the input coordinate list. - * If the distance tolerance is positive, - * concavities on the LEFT side of the line are simplified. - * If the supplied distance tolerance is negative, - * concavities on the RIGHT side of the line are simplified. - * - * @param distanceTol simplification distance tolerance to use - * @return the simplified coordinate list - */ - public Coordinate[] simplify(double distanceTol) - { - this.distanceTol = Math.abs(distanceTol); - if (distanceTol < 0) - angleOrientation = CGAlgorithms.CLOCKWISE; - - // rely on fact that boolean array is filled with false value - isDeleted = new byte[inputLine.length]; - - boolean isChanged = false; - do { - isChanged = deleteShallowConcavities(); - } while (isChanged); - - return collapseLine(); - } - - /** - * Uses a sliding window containing 3 vertices to detect shallow angles - * in which the middle vertex can be deleted, since it does not - * affect the shape of the resulting buffer in a significant way. - * @return - */ - private boolean deleteShallowConcavities() - { - /** - * Do not simplify end line segments of the line string. - * This ensures that end caps are generated consistently. - */ - int index = 1; - int maxIndex = inputLine.length - 1; - - int midIndex = findNextNonDeletedIndex(index); - int lastIndex = findNextNonDeletedIndex(midIndex); - - boolean isChanged = false; - while (lastIndex < inputLine.length) { - // test triple for shallow concavity - boolean isMiddleVertexDeleted = false; - if (isDeletable(index, midIndex, lastIndex, - distanceTol)) { - isDeleted[midIndex] = DELETE; - isMiddleVertexDeleted = true; - isChanged = true; - } - // move simplification window forward - if (isMiddleVertexDeleted) - index = lastIndex; - else - index = midIndex; - - midIndex = findNextNonDeletedIndex(index); - lastIndex = findNextNonDeletedIndex(midIndex); - } - return isChanged; - } - - /** - * Finds the next non-deleted index, or the end of the point array if none - * @param index - * @return the next non-deleted index, if any - * or inputLine.length if there are no more non-deleted indices - */ - private int findNextNonDeletedIndex(int index) - { - int next = index + 1; - while (next < inputLine.length && isDeleted[next] == DELETE) - next++; - return next; - } - - private Coordinate[] collapseLine() - { - CoordinateList coordList = new CoordinateList(); - for (int i = 0; i < inputLine.length; i++) { - if (isDeleted[i] != DELETE) - coordList.add(inputLine[i]); - } -// if (coordList.size() < inputLine.length) System.out.println("Simplified " + (inputLine.length - coordList.size()) + " pts"); - return coordList.toCoordinateArray(); - } - - private boolean isDeletable(int i0, int i1, int i2, double distanceTol) - { - Coordinate p0 = inputLine[i0]; - Coordinate p1 = inputLine[i1]; - Coordinate p2 = inputLine[i2]; - - if (! isConcave(p0, p1, p2)) return false; - if (! isShallow(p0, p1, p2, distanceTol)) return false; - - // MD - don't use this heuristic - it's too restricting -// if (p0.distance(p2) > distanceTol) return false; - - return isShallowSampled(p0, p1, i0, i2, distanceTol); - } - - private boolean isShallowConcavity(Coordinate p0, Coordinate p1, Coordinate p2, double distanceTol) - { - int orientation = CGAlgorithms.computeOrientation(p0, p1, p2); - boolean isAngleToSimplify = (orientation == angleOrientation); - if (! isAngleToSimplify) - return false; - - double dist = CGAlgorithms.distancePointLine(p1, p0, p2); - return dist < distanceTol; - } - - private static final int NUM_PTS_TO_CHECK = 10; - - /** - * Checks for shallowness over a sample of points in the given section. - * This helps prevents the siplification from incrementally - * "skipping" over points which are in fact non-shallow. - * - * @param p0 start coordinate of section - * @param p2 end coordinate of section - * @param i0 start index of section - * @param i2 end index of section - * @param distanceTol distance tolerance - * @return - */ - private boolean isShallowSampled(Coordinate p0, Coordinate p2, int i0, int i2, double distanceTol) - { - // check every n'th point to see if it is within tolerance - int inc = (i2 - i0) / NUM_PTS_TO_CHECK; - if (inc <= 0) inc = 1; - - for (int i = i0; i < i2; i += inc) { - if (! isShallow(p0, p2, inputLine[i], distanceTol)) return false; - } - return true; - } - - private boolean isShallow(Coordinate p0, Coordinate p1, Coordinate p2, double distanceTol) - { - double dist = CGAlgorithms.distancePointLine(p1, p0, p2); - return dist < distanceTol; - } - - - private boolean isConcave(Coordinate p0, Coordinate p1, Coordinate p2) - { - int orientation = CGAlgorithms.computeOrientation(p0, p1, p2); - boolean isConcave = (orientation == angleOrientation); - return isConcave; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferOp.java b/src/main/java/com/vividsolutions/jts/operation/buffer/BufferOp.java deleted file mode 100644 index 4367cd07d3..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferOp.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * @version 1.7 - */ -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer; -import com.vividsolutions.jts.math.MathUtil; -import com.vividsolutions.jts.noding.*; -import com.vividsolutions.jts.noding.snapround.*; - -//import debug.*; - -/** - * Computes the buffer of a geometry, for both positive and negative buffer distances. - *

                    - * In GIS, the positive (or negative) buffer of a geometry is defined as - * the Minkowski sum (or difference) of the geometry - * with a circle of radius equal to the absolute value of the buffer distance. - * In the CAD/CAM world buffers are known as offset curves. - * In morphological analysis the - * operation of positive and negative buffering - * is referred to as erosion and dilation - *

                    - * The buffer operation always returns a polygonal result. - * The negative or zero-distance buffer of lines and points is always an empty {@link Polygon}. - *

                    - * Since true buffer curves may contain circular arcs, - * computed buffer polygons are only approximations to the true geometry. - * The user can control the accuracy of the approximation by specifying - * the number of linear segments used to approximate arcs. - * This is specified via {@link BufferParameters#setQuadrantSegments(int)} or {@link #setQuadrantSegments(int)}. - *

                    - * The end cap style of a linear buffer may be {@link BufferParameters#setEndCapStyle(int) specified}. The - * following end cap styles are supported: - *

                      {@link BufferParameters#CAP_ROUND} - the usual round end caps - *
                    • {@link BufferParameters#CAP_BUTT} - end caps are truncated flat at the line ends - *
                    • {@link BufferParameters#CAP_SQUARE} - end caps are squared off at the buffer distance beyond the line ends - *
                    - *

                    - * The join style of the corners in a buffer may be {@link BufferParameters#setJoinStyle(int) specified}. The - * following join styles are supported: - *

                      {@link BufferParameters#JOIN_ROUND} - the usual round join - *
                    • {@link BufferParameters#JOIN_MITRE} - corners are "sharp" (up to a {@link BufferParameters#getMitreLimit() distance limit}) - *
                    • {@link BufferParameters#JOIN_BEVEL} - corners are beveled (clipped off). - *
                    - *

                    - * The buffer algorithm can perform simplification on the input to increase performance. - * The simplification is performed a way that always increases the buffer area - * (so that the simplified input covers the original input). - * The degree of simplification can be {@link BufferParameters#setSimplifyFactor(double) specified}, - * with a {@link BufferParameters#DEFAULT_SIMPLIFY_FACTOR default} used otherwise. - * Note that if the buffer distance is zero then so is the computed simplify tolerance, - * no matter what the simplify factor. - * - * @version 1.7 - */ -public class BufferOp -{ - /** - * Specifies a round line buffer end cap style. - * @deprecated use BufferParameters - */ - public static final int CAP_ROUND = BufferParameters.CAP_ROUND; - /** - * Specifies a butt (or flat) line buffer end cap style. - * @deprecated use BufferParameters - */ - public static final int CAP_BUTT = BufferParameters.CAP_FLAT; - - /** - * Specifies a butt (or flat) line buffer end cap style. - * @deprecated use BufferParameters - */ - public static final int CAP_FLAT = BufferParameters.CAP_FLAT; - /** - * Specifies a square line buffer end cap style. - * @deprecated use BufferParameters - */ - public static final int CAP_SQUARE = BufferParameters.CAP_SQUARE; - - /** - * A number of digits of precision which leaves some computational "headroom" - * for floating point operations. - * - * This value should be less than the decimal precision of double-precision values (16). - */ - private static int MAX_PRECISION_DIGITS = 12; - - /** - * Compute a scale factor to limit the precision of - * a given combination of Geometry and buffer distance. - * The scale factor is determined by - * the number of digits of precision in the (geometry + buffer distance), - * limited by the supplied maxPrecisionDigits value. - *

                    - * The scale factor is based on the absolute magnitude of the (geometry + buffer distance). - * since this determines the number of digits of precision which must be handled. - * - * @param g the Geometry being buffered - * @param distance the buffer distance - * @param maxPrecisionDigits the max # of digits that should be allowed by - * the precision determined by the computed scale factor - * - * @return a scale factor for the buffer computation - */ - private static double precisionScaleFactor(Geometry g, - double distance, - int maxPrecisionDigits) - { - Envelope env = g.getEnvelopeInternal(); - double envMax = MathUtil.max( - Math.abs(env.getMaxX()), - Math.abs(env.getMaxY()), - Math.abs(env.getMinX()), - Math.abs(env.getMinY()) - ); - - double expandByDistance = distance > 0.0 ? distance : 0.0; - double bufEnvMax = envMax + 2 * expandByDistance; - - // the smallest power of 10 greater than the buffer envelope - int bufEnvPrecisionDigits = (int) (Math.log(bufEnvMax) / Math.log(10) + 1.0); - int minUnitLog10 = maxPrecisionDigits - bufEnvPrecisionDigits; - - double scaleFactor = Math.pow(10.0, minUnitLog10); - return scaleFactor; - } - - /* - private static double OLDprecisionScaleFactor(Geometry g, - double distance, - int maxPrecisionDigits) - { - Envelope env = g.getEnvelopeInternal(); - double envSize = Math.max(env.getHeight(), env.getWidth()); - double expandByDistance = distance > 0.0 ? distance : 0.0; - double bufEnvSize = envSize + 2 * expandByDistance; - - // the smallest power of 10 greater than the buffer envelope - int bufEnvLog10 = (int) (Math.log(bufEnvSize) / Math.log(10) + 1.0); - int minUnitLog10 = bufEnvLog10 - maxPrecisionDigits; - // scale factor is inverse of min Unit size, so flip sign of exponent - double scaleFactor = Math.pow(10.0, -minUnitLog10); - return scaleFactor; - } - */ - - /** - * Computes the buffer of a geometry for a given buffer distance. - * - * @param g the geometry to buffer - * @param distance the buffer distance - * @return the buffer of the input geometry - */ - public static Geometry bufferOp(Geometry g, double distance) - { - BufferOp gBuf = new BufferOp(g); - Geometry geomBuf = gBuf.getResultGeometry(distance); -//BufferDebug.saveBuffer(geomBuf); - //BufferDebug.runCount++; - return geomBuf; - } - - /** - * Comutes the buffer for a geometry for a given buffer distance - * and accuracy of approximation. - * - * @param g the geometry to buffer - * @param distance the buffer distance - * @param params the buffer parameters to use - * @return the buffer of the input geometry - * - */ - public static Geometry bufferOp(Geometry g, double distance, BufferParameters params) - { - BufferOp bufOp = new BufferOp(g, params); - Geometry geomBuf = bufOp.getResultGeometry(distance); - return geomBuf; - } - - /** - * Comutes the buffer for a geometry for a given buffer distance - * and accuracy of approximation. - * - * @param g the geometry to buffer - * @param distance the buffer distance - * @param quadrantSegments the number of segments used to approximate a quarter circle - * @return the buffer of the input geometry - * - */ - public static Geometry bufferOp(Geometry g, double distance, int quadrantSegments) - { - BufferOp bufOp = new BufferOp(g); - bufOp.setQuadrantSegments(quadrantSegments); - Geometry geomBuf = bufOp.getResultGeometry(distance); - return geomBuf; - } - - /** - * Comutes the buffer for a geometry for a given buffer distance - * and accuracy of approximation. - * - * @param g the geometry to buffer - * @param distance the buffer distance - * @param quadrantSegments the number of segments used to approximate a quarter circle - * @param endCapStyle the end cap style to use - * @return the buffer of the input geometry - * - */ - public static Geometry bufferOp(Geometry g, - double distance, - int quadrantSegments, - int endCapStyle) - { - BufferOp bufOp = new BufferOp(g); - bufOp.setQuadrantSegments(quadrantSegments); - bufOp.setEndCapStyle(endCapStyle); - Geometry geomBuf = bufOp.getResultGeometry(distance); - return geomBuf; - } - - private Geometry argGeom; - private double distance; - - private BufferParameters bufParams = new BufferParameters(); - - private Geometry resultGeometry = null; - private RuntimeException saveException; // debugging only - - /** - * Initializes a buffer computation for the given geometry - * - * @param g the geometry to buffer - */ - public BufferOp(Geometry g) { - argGeom = g; - } - - /** - * Initializes a buffer computation for the given geometry - * with the given set of parameters - * - * @param g the geometry to buffer - * @param bufParams the buffer parameters to use - */ - public BufferOp(Geometry g, BufferParameters bufParams) { - argGeom = g; - this.bufParams = bufParams; - } - - /** - * Specifies the end cap style of the generated buffer. - * The styles supported are {@link BufferParameters#CAP_ROUND}, {@link BufferParameters##CAP_BUTT}, and {@link BufferParameters##CAP_SQUARE}. - * The default is CAP_ROUND. - * - * @param endCapStyle the end cap style to specify - */ - public void setEndCapStyle(int endCapStyle) - { - bufParams.setEndCapStyle(endCapStyle); - } - - /** - * Sets the number of segments used to approximate a angle fillet - * - * @param quadrantSegments the number of segments in a fillet for a quadrant - */ - public void setQuadrantSegments(int quadrantSegments) - { - bufParams.setQuadrantSegments(quadrantSegments); - } - - /** - * Returns the buffer computed for a geometry for a given buffer distance. - * - * @param distance the buffer distance - * @return the buffer of the input geometry - */ - public Geometry getResultGeometry(double distance) - { - this.distance = distance; - computeGeometry(); - return resultGeometry; - } - - private void computeGeometry() - { - bufferOriginalPrecision(); - if (resultGeometry != null) return; - - PrecisionModel argPM = argGeom.getFactory().getPrecisionModel(); - if (argPM.getType() == PrecisionModel.FIXED) - bufferFixedPrecision(argPM); - else - bufferReducedPrecision(); - } - - private void bufferReducedPrecision() - { - // try and compute with decreasing precision - for (int precDigits = MAX_PRECISION_DIGITS; precDigits >= 0; precDigits--) { - try { - bufferReducedPrecision(precDigits); - } - catch (TopologyException ex) { - // update the saved exception to reflect the new input geometry - saveException = ex; - // don't propagate the exception - it will be detected by fact that resultGeometry is null - } - if (resultGeometry != null) return; - } - - // tried everything - have to bail - throw saveException; - } - - private void bufferOriginalPrecision() - { - try { - // use fast noding by default - BufferBuilder bufBuilder = new BufferBuilder(bufParams); - resultGeometry = bufBuilder.buffer(argGeom, distance); - } - catch (RuntimeException ex) { - saveException = ex; - // don't propagate the exception - it will be detected by fact that resultGeometry is null - - // testing ONLY - propagate exception - //throw ex; - } - } - - private void bufferReducedPrecision(int precisionDigits) - { - double sizeBasedScaleFactor = precisionScaleFactor(argGeom, distance, precisionDigits); -// System.out.println("recomputing with precision scale factor = " + sizeBasedScaleFactor); - - PrecisionModel fixedPM = new PrecisionModel(sizeBasedScaleFactor); - bufferFixedPrecision(fixedPM); - } - - private void bufferFixedPrecision(PrecisionModel fixedPM) - { - Noder noder = new ScaledNoder(new MCIndexSnapRounder(new PrecisionModel(1.0)), - fixedPM.getScale()); - - BufferBuilder bufBuilder = new BufferBuilder(bufParams); - bufBuilder.setWorkingPrecisionModel(fixedPM); - bufBuilder.setNoder(noder); - // this may throw an exception, if robustness errors are encountered - resultGeometry = bufBuilder.buffer(argGeom, distance); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferParameters.java b/src/main/java/com/vividsolutions/jts/operation/buffer/BufferParameters.java deleted file mode 100644 index 2c5759ad72..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferParameters.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * A value class containing the parameters which - * specify how a buffer should be constructed. - *

                    - * The parameters allow control over: - *

                      - *
                    • Quadrant segments (accuracy of approximation for circular arcs) - *
                    • End Cap style - *
                    • Join style - *
                    • Mitre limit - *
                    • whether the buffer is single-sided - *
                    - * - * @author Martin Davis - * - */ -public class BufferParameters -{ - /** - * Specifies a round line buffer end cap style. - */ - public static final int CAP_ROUND = 1; - /** - * Specifies a flat line buffer end cap style. - */ - public static final int CAP_FLAT = 2; - /** - * Specifies a square line buffer end cap style. - */ - public static final int CAP_SQUARE = 3; - - /** - * Specifies a round join style. - */ - public static final int JOIN_ROUND = 1; - /** - * Specifies a mitre join style. - */ - public static final int JOIN_MITRE = 2; - /** - * Specifies a bevel join style. - */ - public static final int JOIN_BEVEL = 3; - - /** - * The default number of facets into which to divide a fillet of 90 degrees. - * A value of 8 gives less than 2% max error in the buffer distance. - * For a max error of < 1%, use QS = 12. - * For a max error of < 0.1%, use QS = 18. - */ - public static final int DEFAULT_QUADRANT_SEGMENTS = 8; - - /** - * The default mitre limit - * Allows fairly pointy mitres. - */ - public static final double DEFAULT_MITRE_LIMIT = 5.0; - - /** - * The default simplify factor - * Provides an accuracy of about 1%, which matches the accuracy of the default Quadrant Segments parameter. - */ - public static final double DEFAULT_SIMPLIFY_FACTOR = 0.01; - - - private int quadrantSegments = DEFAULT_QUADRANT_SEGMENTS; - private int endCapStyle = CAP_ROUND; - private int joinStyle = JOIN_ROUND; - private double mitreLimit = DEFAULT_MITRE_LIMIT; - private boolean isSingleSided = false; - private double simplifyFactor = DEFAULT_SIMPLIFY_FACTOR; - - /** - * Creates a default set of parameters - * - */ - public BufferParameters() { - } - - /** - * Creates a set of parameters with the - * given quadrantSegments value. - * - * @param quadrantSegments the number of quadrant segments to use - */ - public BufferParameters(int quadrantSegments) - { - setQuadrantSegments(quadrantSegments); - } - - /** - * Creates a set of parameters with the - * given quadrantSegments and endCapStyle values. - * - * @param quadrantSegments the number of quadrant segments to use - * @param endCapStyle the end cap style to use - */ - public BufferParameters(int quadrantSegments, - int endCapStyle) - { - setQuadrantSegments(quadrantSegments); - setEndCapStyle(endCapStyle); - } - - /** - * Creates a set of parameters with the - * given parameter values. - * - * @param quadrantSegments the number of quadrant segments to use - * @param endCapStyle the end cap style to use - * @param joinStyle the join style to use - * @param mitreLimit the mitre limit to use - */ - public BufferParameters(int quadrantSegments, - int endCapStyle, - int joinStyle, - double mitreLimit) - { - setQuadrantSegments(quadrantSegments); - setEndCapStyle(endCapStyle); - setJoinStyle(joinStyle); - setMitreLimit(mitreLimit); - } - - /** - * Gets the number of quadrant segments which will be used - * - * @return the number of quadrant segments - */ - public int getQuadrantSegments() - { - return quadrantSegments; - } - - /** - * Sets the number of line segments used to approximate an angle fillet. - *
                      - *
                    • If quadSegs >= 1, joins are round, and quadSegs indicates the number of - * segments to use to approximate a quarter-circle. - *
                    • If quadSegs = 0, joins are bevelled (flat) - *
                    • If quadSegs < 0, joins are mitred, and the value of qs - * indicates the mitre ration limit as - *
                      -   * mitreLimit = |quadSegs|
                      -   * 
                      - *
                    - * For round joins, quadSegs determines the maximum - * error in the approximation to the true buffer curve. - * The default value of 8 gives less than 2% max error in the buffer distance. - * For a max error of < 1%, use QS = 12. - * For a max error of < 0.1%, use QS = 18. - * The error is always less than the buffer distance - * (in other words, the computed buffer curve is always inside the true - * curve). - * - * @param quadSegs the number of segments in a fillet for a quadrant - */ - public void setQuadrantSegments(int quadSegs) - { - quadrantSegments = quadSegs; - - /** - * Indicates how to construct fillets. - * If qs >= 1, fillet is round, and qs indicates number of - * segments to use to approximate a quarter-circle. - * If qs = 0, fillet is bevelled flat (i.e. no filleting is performed) - * If qs < 0, fillet is mitred, and absolute value of qs - * indicates maximum length of mitre according to - * - * mitreLimit = |qs| - */ - if (quadrantSegments == 0) - joinStyle = JOIN_BEVEL; - if (quadrantSegments < 0) { - joinStyle = JOIN_MITRE; - mitreLimit = Math.abs(quadrantSegments); - } - - if (quadSegs <= 0) { - quadrantSegments = 1; - } - - /** - * If join style was set by the quadSegs value, - * use the default for the actual quadrantSegments value. - */ - if (joinStyle != JOIN_ROUND) { - quadrantSegments = DEFAULT_QUADRANT_SEGMENTS; - } - } - - /** - * Computes the maximum distance error due to a given level - * of approximation to a true arc. - * - * @param quadSegs the number of segments used to approximate a quarter-circle - * @return the error of approximation - */ - public static double bufferDistanceError(int quadSegs) - { - double alpha = Math.PI / 2.0 / quadSegs; - return 1 - Math.cos(alpha / 2.0); - } - - /** - * Gets the end cap style. - * - * @return the end cap style - */ - public int getEndCapStyle() - { - return endCapStyle; - } - - /** - * Specifies the end cap style of the generated buffer. - * The styles supported are {@link #CAP_ROUND}, {@link #CAP_FLAT}, and {@link #CAP_SQUARE}. - * The default is CAP_ROUND. - * - * @param endCapStyle the end cap style to specify - */ - public void setEndCapStyle(int endCapStyle) - { - this.endCapStyle = endCapStyle; - } - - /** - * Gets the join style - * - * @return the join style code - */ - public int getJoinStyle() - { - return joinStyle; - } - - /** - * Sets the join style for outside (reflex) corners between line segments. - * Allowable values are {@link #JOIN_ROUND} (which is the default), - * {@link #JOIN_MITRE} and {link JOIN_BEVEL}. - * - * @param joinStyle the code for the join style - */ - public void setJoinStyle(int joinStyle) - { - this.joinStyle = joinStyle; - } - - /** - * Gets the mitre ratio limit. - * - * @return the limit value - */ - public double getMitreLimit() - { - return mitreLimit; - } - - /** - * Sets the limit on the mitre ratio used for very sharp corners. - * The mitre ratio is the ratio of the distance from the corner - * to the end of the mitred offset corner. - * When two line segments meet at a sharp angle, - * a miter join will extend far beyond the original geometry. - * (and in the extreme case will be infinitely far.) - * To prevent unreasonable geometry, the mitre limit - * allows controlling the maximum length of the join corner. - * Corners with a ratio which exceed the limit will be beveled. - * - * @param mitreLimit the mitre ratio limit - */ - public void setMitreLimit(double mitreLimit) - { - this.mitreLimit = mitreLimit; - } - - /** - * Sets whether the computed buffer should be single-sided. - * A single-sided buffer is constructed on only one side of each input line. - *

                    - * The side used is determined by the sign of the buffer distance: - *

                      - *
                    • a positive distance indicates the left-hand side - *
                    • a negative distance indicates the right-hand side - *
                    - * The single-sided buffer of point geometries is - * the same as the regular buffer. - *

                    - * The End Cap Style for single-sided buffers is - * always ignored, - * and forced to the equivalent of CAP_FLAT. - * - * @param isSingleSided true if a single-sided buffer should be constructed - */ - public void setSingleSided(boolean isSingleSided) - { - this.isSingleSided = isSingleSided; - } - - /** - * Tests whether the buffer is to be generated on a single side only. - * - * @return true if the generated buffer is to be single-sided - */ - public boolean isSingleSided() { - return isSingleSided; - } - - /** - * Gets the simplify factor. - * - * @return the simplify factor - */ - public double getSimplifyFactor() { - return simplifyFactor; - } - - /** - * Sets the factor used to determine the simplify distance tolerance - * for input simplification. - * Simplifying can increase the performance of computing buffers. - * Generally the simplify factor should be greater than 0. - * Values between 0.01 and .1 produce relatively good accuracy for the generate buffer. - * Larger values sacrifice accuracy in return for performance. - * - * @param simplifyFactor a value greater than or equal to zero. - */ - public void setSimplifyFactor(double simplifyFactor) - { - this.simplifyFactor = simplifyFactor < 0 ? 0 : simplifyFactor; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java b/src/main/java/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java deleted file mode 100644 index 7f801f60f9..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java +++ /dev/null @@ -1,330 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * @version 1.7 - */ - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.*; -//import debug.*; - -/** - * A connected subset of the graph of - * {@link DirectedEdge}s and {@link Node}s. - * Its edges will generate either - *

                      - *
                    • a single polygon in the complete buffer, with zero or more holes, or - *
                    • one or more connected holes - *
                    - * - * - * @version 1.7 - */ -class BufferSubgraph - implements Comparable -{ - private RightmostEdgeFinder finder; - private List dirEdgeList = new ArrayList(); - private List nodes = new ArrayList(); - private Coordinate rightMostCoord = null; - private Envelope env = null; - - public BufferSubgraph() - { - finder = new RightmostEdgeFinder(); - } - - public List getDirectedEdges() { return dirEdgeList; } - public List getNodes() { return nodes; } - - /** - * Computes the envelope of the edges in the subgraph. - * The envelope is cached after being computed. - * - * @return the envelope of the graph. - */ - public Envelope getEnvelope() - { - if (env == null) { - Envelope edgeEnv = new Envelope(); - for (Iterator it = dirEdgeList.iterator(); it.hasNext(); ) { - DirectedEdge dirEdge = (DirectedEdge) it.next(); - Coordinate[] pts = dirEdge.getEdge().getCoordinates(); - for (int i = 0; i < pts.length - 1; i++) { - edgeEnv.expandToInclude(pts[i]); - } - } - env = edgeEnv; - } - return env; - } - - /** - * Gets the rightmost coordinate in the edges of the subgraph - */ - public Coordinate getRightmostCoordinate() - { - return rightMostCoord; - } - - /** - * Creates the subgraph consisting of all edges reachable from this node. - * Finds the edges in the graph and the rightmost coordinate. - * - * @param node a node to start the graph traversal from - */ - public void create(Node node) - { - addReachable(node); - finder.findEdge(dirEdgeList); - rightMostCoord = finder.getCoordinate(); - } - - /** - * Adds all nodes and edges reachable from this node to the subgraph. - * Uses an explicit stack to avoid a large depth of recursion. - * - * @param node a node known to be in the subgraph - */ - private void addReachable(Node startNode) - { - Stack nodeStack = new Stack(); - nodeStack.add(startNode); - while (! nodeStack.empty()) { - Node node = (Node) nodeStack.pop(); - add(node, nodeStack); - } - } - - /** - * Adds the argument node and all its out edges to the subgraph - * @param node the node to add - * @param nodeStack the current set of nodes being traversed - */ - private void add(Node node, Stack nodeStack) - { - node.setVisited(true); - nodes.add(node); - for (Iterator i = ((DirectedEdgeStar) node.getEdges()).iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - dirEdgeList.add(de); - DirectedEdge sym = de.getSym(); - Node symNode = sym.getNode(); - /** - * NOTE: this is a depth-first traversal of the graph. - * This will cause a large depth of recursion. - * It might be better to do a breadth-first traversal. - */ - if (! symNode.isVisited()) nodeStack.push(symNode); - } - } - - private void clearVisitedEdges() - { - for (Iterator it = dirEdgeList.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - de.setVisited(false); - } - } - - public void computeDepth(int outsideDepth) - { - clearVisitedEdges(); - // find an outside edge to assign depth to - DirectedEdge de = finder.getEdge(); - Node n = de.getNode(); - Label label = de.getLabel(); - // right side of line returned by finder is on the outside - de.setEdgeDepths(Position.RIGHT, outsideDepth); - copySymDepths(de); - - //computeNodeDepth(n, de); - computeDepths(de); - } - - /** - * Compute depths for all dirEdges via breadth-first traversal of nodes in graph - * @param startEdge edge to start processing with - */ - // MD - use iteration & queue rather than recursion, for speed and robustness - private void computeDepths(DirectedEdge startEdge) - { - Set nodesVisited = new HashSet(); - LinkedList nodeQueue = new LinkedList(); - - Node startNode = startEdge.getNode(); - nodeQueue.addLast(startNode); - nodesVisited.add(startNode); - startEdge.setVisited(true); - - while (! nodeQueue.isEmpty()) { -//System.out.println(nodes.size() + " queue: " + nodeQueue.size()); - Node n = (Node) nodeQueue.removeFirst(); - nodesVisited.add(n); - // compute depths around node, starting at this edge since it has depths assigned - computeNodeDepth(n); - - // add all adjacent nodes to process queue, - // unless the node has been visited already - for (Iterator i = ((DirectedEdgeStar) n.getEdges()).iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - DirectedEdge sym = de.getSym(); - if (sym.isVisited()) continue; - Node adjNode = sym.getNode(); - if (! (nodesVisited.contains(adjNode)) ) { - nodeQueue.addLast(adjNode); - nodesVisited.add(adjNode); - } - } - } - } - - private void computeNodeDepth(Node n) - { - // find a visited dirEdge to start at - DirectedEdge startEdge = null; - for (Iterator i = ((DirectedEdgeStar) n.getEdges()).iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - if (de.isVisited() || de.getSym().isVisited()) { - startEdge = de; - break; - } - } - // MD - testing Result: breaks algorithm - //if (startEdge == null) return; - - // only compute string append if assertion would fail - if (startEdge == null) - throw new TopologyException("unable to find edge to compute depths at " + n.getCoordinate()); - - ((DirectedEdgeStar) n.getEdges()).computeDepths(startEdge); - - // copy depths to sym edges - for (Iterator i = ((DirectedEdgeStar) n.getEdges()).iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - de.setVisited(true); - copySymDepths(de); - } - } - - private void copySymDepths(DirectedEdge de) - { - DirectedEdge sym = de.getSym(); - sym.setDepth(Position.LEFT, de.getDepth(Position.RIGHT)); - sym.setDepth(Position.RIGHT, de.getDepth(Position.LEFT)); - } - - /** - * Find all edges whose depths indicates that they are in the result area(s). - * Since we want polygon shells to be - * oriented CW, choose dirEdges with the interior of the result on the RHS. - * Mark them as being in the result. - * Interior Area edges are the result of dimensional collapses. - * They do not form part of the result area boundary. - */ - public void findResultEdges() - { - for (Iterator it = dirEdgeList.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - /** - * Select edges which have an interior depth on the RHS - * and an exterior depth on the LHS. - * Note that because of weird rounding effects there may be - * edges which have negative depths! Negative depths - * count as "outside". - */ - // - handle negative depths - if ( de.getDepth(Position.RIGHT) >= 1 - && de.getDepth(Position.LEFT) <= 0 - && ! de.isInteriorAreaEdge()) { - de.setInResult(true); -//Debug.print("in result "); Debug.println(de); - } - } - } - - /** - * BufferSubgraphs are compared on the x-value of their rightmost Coordinate. - * This defines a partial ordering on the graphs such that: - *

                    - * g1 >= g2 <==> Ring(g2) does not contain Ring(g1) - *

                    - * where Polygon(g) is the buffer polygon that is built from g. - *

                    - * This relationship is used to sort the BufferSubgraphs so that shells are guaranteed to - * be built before holes. - */ - public int compareTo(Object o) { - BufferSubgraph graph = (BufferSubgraph) o; - if (this.rightMostCoord.x < graph.rightMostCoord.x) { - return -1; - } - if (this.rightMostCoord.x > graph.rightMostCoord.x) { - return 1; - } - return 0; - } - -/* -// DEBUGGING only - comment out - private static final String SAVE_DIREDGES = "saveDirEdges"; - private static int saveCount = 0; - public void saveDirEdges() - { - GeometryFactory fact = new GeometryFactory(); - for (Iterator it = dirEdgeList.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - double dx = de.getDx(); - double dy = de.getDy(); - Coordinate p0 = de.getCoordinate(); - double ang = Math.atan2(dy, dx); - Coordinate p1 = new Coordinate( - p0.x + .4 * Math.cos(ang), - p0.y + .4 * Math.sin(ang)); -// DebugFeature.add(SAVE_DIREDGES, -// fact.createLineString(new Coordinate[] { p0, p1 } ), -// de.getDepth(Position.LEFT) + "/" + de.getDepth(Position.RIGHT) -// ); - } - String filepath = "x:\\jts\\testBuffer\\dirEdges" + saveCount++ + ".jml"; - DebugFeature.saveFeatures(SAVE_DIREDGES, filepath); - } - */ -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java deleted file mode 100644 index c2c354da01..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateArrays; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.PrecisionModel; -import com.vividsolutions.jts.geomgraph.Position; - -/** - * Computes the raw offset curve for a - * single {@link Geometry} component (ring, line or point). - * A raw offset curve line is not noded - - * it may contain self-intersections (and usually will). - * The final buffer polygon is computed by forming a topological graph - * of all the noded raw curves and tracing outside contours. - * The points in the raw curve are rounded - * to a given {@link PrecisionModel}. - * - * @version 1.7 - */ -public class OffsetCurveBuilder -{ - private double distance = 0.0; - private PrecisionModel precisionModel; - private BufferParameters bufParams; - - public OffsetCurveBuilder( - PrecisionModel precisionModel, - BufferParameters bufParams - ) - { - this.precisionModel = precisionModel; - this.bufParams = bufParams; - } - - /** - * Gets the buffer parameters being used to generate the curve. - * - * @return the buffer parameters being used - */ - public BufferParameters getBufferParameters() - { - return bufParams; - } - - /** - * This method handles single points as well as LineStrings. - * LineStrings are assumed not to be closed (the function will not - * fail for closed lines, but will generate superfluous line caps). - * - * @param inputPts the vertices of the line to offset - * @param distance the offset distance - * - * @return a Coordinate array representing the curve - * or null if the curve is empty - */ - public Coordinate[] getLineCurve(Coordinate[] inputPts, double distance) - { - this.distance = distance; - - // a zero or negative width buffer of a line/point is empty - if (distance < 0.0 && ! bufParams.isSingleSided()) return null; - if (distance == 0.0) return null; - - double posDistance = Math.abs(distance); - OffsetSegmentGenerator segGen = getSegGen(posDistance); - if (inputPts.length <= 1) { - computePointCurve(inputPts[0], segGen); - } - else { - if (bufParams.isSingleSided()) { - boolean isRightSide = distance < 0.0; - computeSingleSidedBufferCurve(inputPts, isRightSide, segGen); - } - else - computeLineBufferCurve(inputPts, segGen); - } - - Coordinate[] lineCoord = segGen.getCoordinates(); - return lineCoord; - } - - /** - * This method handles the degenerate cases of single points and lines, - * as well as rings. - * - * @return a Coordinate array representing the curve - * or null if the curve is empty - */ - public Coordinate[] getRingCurve(Coordinate[] inputPts, int side, double distance) - { - this.distance = distance; - if (inputPts.length <= 2) - return getLineCurve(inputPts, distance); - - // optimize creating ring for for zero distance - if (distance == 0.0) { - return copyCoordinates(inputPts); - } - OffsetSegmentGenerator segGen = getSegGen(distance); - computeRingBufferCurve(inputPts, side, segGen); - return segGen.getCoordinates(); - } - - public Coordinate[] getOffsetCurve(Coordinate[] inputPts, double distance) - { - this.distance = distance; - - // a zero width offset curve is empty - if (distance == 0.0) return null; - - boolean isRightSide = distance < 0.0; - double posDistance = Math.abs(distance); - OffsetSegmentGenerator segGen = getSegGen(posDistance); - if (inputPts.length <= 1) { - computePointCurve(inputPts[0], segGen); - } - else { - computeOffsetCurve(inputPts, isRightSide, segGen); - } - Coordinate[] curvePts = segGen.getCoordinates(); - // for right side line is traversed in reverse direction, so have to reverse generated line - if (isRightSide) - CoordinateArrays.reverse(curvePts); - return curvePts; - } - - private static Coordinate[] copyCoordinates(Coordinate[] pts) - { - Coordinate[] copy = new Coordinate[pts.length]; - for (int i = 0; i < copy.length; i++) { - copy[i] = new Coordinate(pts[i]); - } - return copy; - } - - private OffsetSegmentGenerator getSegGen(double distance) - { - return new OffsetSegmentGenerator(precisionModel, bufParams, distance); - } - - /** - * Computes the distance tolerance to use during input - * line simplification. - * - * @param distance the buffer distance - * @return the simplification tolerance - */ - private double simplifyTolerance(double bufDistance) - { - return bufDistance * bufParams.getSimplifyFactor(); - } - - private void computePointCurve(Coordinate pt, OffsetSegmentGenerator segGen) { - switch (bufParams.getEndCapStyle()) { - case BufferParameters.CAP_ROUND: - segGen.createCircle(pt); - break; - case BufferParameters.CAP_SQUARE: - segGen.createSquare(pt); - break; - // otherwise curve is empty (e.g. for a butt cap); - } - } - - private void computeLineBufferCurve(Coordinate[] inputPts, OffsetSegmentGenerator segGen) - { - double distTol = simplifyTolerance(distance); - - //--------- compute points for left side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); - // MD - used for testing only (to eliminate simplification) -// Coordinate[] simp1 = inputPts; - - int n1 = simp1.length - 1; - segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); - for (int i = 2; i <= n1; i++) { - segGen.addNextSegment(simp1[i], true); - } - segGen.addLastSegment(); - // add line cap for end of line - segGen.addLineEndCap(simp1[n1 - 1], simp1[n1]); - - //---------- compute points for right side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); - // MD - used for testing only (to eliminate simplification) -// Coordinate[] simp2 = inputPts; - int n2 = simp2.length - 1; - - // since we are traversing line in opposite order, offset position is still LEFT - segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); - for (int i = n2 - 2; i >= 0; i--) { - segGen.addNextSegment(simp2[i], true); - } - segGen.addLastSegment(); - // add line cap for start of line - segGen.addLineEndCap(simp2[1], simp2[0]); - - segGen.closeRing(); - } - - /* - private void OLDcomputeLineBufferCurve(Coordinate[] inputPts) - { - int n = inputPts.length - 1; - - // compute points for left side of line - initSideSegments(inputPts[0], inputPts[1], Position.LEFT); - for (int i = 2; i <= n; i++) { - addNextSegment(inputPts[i], true); - } - addLastSegment(); - // add line cap for end of line - addLineEndCap(inputPts[n - 1], inputPts[n]); - - // compute points for right side of line - initSideSegments(inputPts[n], inputPts[n - 1], Position.LEFT); - for (int i = n - 2; i >= 0; i--) { - addNextSegment(inputPts[i], true); - } - addLastSegment(); - // add line cap for start of line - addLineEndCap(inputPts[1], inputPts[0]); - - vertexList.closeRing(); - } - */ - - private void computeSingleSidedBufferCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) - { - double distTol = simplifyTolerance(distance); - - if (isRightSide) { - // add original line - segGen.addSegments(inputPts, true); - - //---------- compute points for right side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); - // MD - used for testing only (to eliminate simplification) - // Coordinate[] simp2 = inputPts; - int n2 = simp2.length - 1; - - // since we are traversing line in opposite order, offset position is still LEFT - segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); - segGen.addFirstSegment(); - for (int i = n2 - 2; i >= 0; i--) { - segGen.addNextSegment(simp2[i], true); - } - } - else { - // add original line - segGen.addSegments(inputPts, false); - - //--------- compute points for left side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); - // MD - used for testing only (to eliminate simplification) -// Coordinate[] simp1 = inputPts; - - int n1 = simp1.length - 1; - segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); - segGen.addFirstSegment(); - for (int i = 2; i <= n1; i++) { - segGen.addNextSegment(simp1[i], true); - } - } - segGen.addLastSegment(); - segGen.closeRing(); - } - - private void computeOffsetCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) - { - double distTol = simplifyTolerance(distance); - - if (isRightSide) { - //---------- compute points for right side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); - // MD - used for testing only (to eliminate simplification) - // Coordinate[] simp2 = inputPts; - int n2 = simp2.length - 1; - - // since we are traversing line in opposite order, offset position is still LEFT - segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); - segGen.addFirstSegment(); - for (int i = n2 - 2; i >= 0; i--) { - segGen.addNextSegment(simp2[i], true); - } - } - else { - //--------- compute points for left side of line - // Simplify the appropriate side of the line before generating - Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); - // MD - used for testing only (to eliminate simplification) -// Coordinate[] simp1 = inputPts; - - int n1 = simp1.length - 1; - segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); - segGen.addFirstSegment(); - for (int i = 2; i <= n1; i++) { - segGen.addNextSegment(simp1[i], true); - } - } - segGen.addLastSegment(); - } - - private void computeRingBufferCurve(Coordinate[] inputPts, int side, OffsetSegmentGenerator segGen) - { - // simplify input line to improve performance - double distTol = simplifyTolerance(distance); - // ensure that correct side is simplified - if (side == Position.RIGHT) - distTol = -distTol; - Coordinate[] simp = BufferInputLineSimplifier.simplify(inputPts, distTol); -// Coordinate[] simp = inputPts; - - int n = simp.length - 1; - segGen.initSideSegments(simp[n - 1], simp[0], side); - for (int i = 1; i <= n; i++) { - boolean addStartPoint = i != 1; - segGen.addNextSegment(simp[i], addStartPoint); - } - segGen.closeRing(); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java deleted file mode 100644 index f491a5db39..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java +++ /dev/null @@ -1,311 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.noding.*; - -/** - * Creates all the raw offset curves for a buffer of a {@link Geometry}. - * Raw curves need to be noded together and polygonized to form the final buffer area. - * - * @version 1.7 - */ -public class OffsetCurveSetBuilder { - - - private Geometry inputGeom; - private double distance; - private OffsetCurveBuilder curveBuilder; - - private List curveList = new ArrayList(); - - public OffsetCurveSetBuilder( - Geometry inputGeom, - double distance, - OffsetCurveBuilder curveBuilder) - { - this.inputGeom = inputGeom; - this.distance = distance; - this.curveBuilder = curveBuilder; - } - - /** - * Computes the set of raw offset curves for the buffer. - * Each offset curve has an attached {@link Label} indicating - * its left and right location. - * - * @return a Collection of SegmentStrings representing the raw buffer curves - */ - public List getCurves() - { - add(inputGeom); - return curveList; - } - - /** - * Creates a {@link SegmentString} for a coordinate list which is a raw offset curve, - * and adds it to the list of buffer curves. - * The SegmentString is tagged with a Label giving the topology of the curve. - * The curve may be oriented in either direction. - * If the curve is oriented CW, the locations will be: - *
                    Left: Location.EXTERIOR - *
                    Right: Location.INTERIOR - */ - private void addCurve(Coordinate[] coord, int leftLoc, int rightLoc) - { - // don't add null or trivial curves - if (coord == null || coord.length < 2) return; - // add the edge for a coordinate list which is a raw offset curve - SegmentString e = new NodedSegmentString(coord, - new Label(0, Location.BOUNDARY, leftLoc, rightLoc)); - curveList.add(e); - } - - - private void add(Geometry g) - { - if (g.isEmpty()) return; - - if (g instanceof Polygon) addPolygon((Polygon) g); - // LineString also handles LinearRings - else if (g instanceof LineString) addLineString((LineString) g); - else if (g instanceof Point) addPoint((Point) g); - else if (g instanceof MultiPoint) addCollection((MultiPoint) g); - else if (g instanceof MultiLineString) addCollection((MultiLineString) g); - else if (g instanceof MultiPolygon) addCollection((MultiPolygon) g); - else if (g instanceof GeometryCollection) addCollection((GeometryCollection) g); - else throw new UnsupportedOperationException(g.getClass().getName()); - } - private void addCollection(GeometryCollection gc) - { - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - add(g); - } - } - /** - * Add a Point to the graph. - */ - private void addPoint(Point p) - { - // a zero or negative width buffer of a line/point is empty - if (distance <= 0.0) - return; - Coordinate[] coord = p.getCoordinates(); - Coordinate[] curve = curveBuilder.getLineCurve(coord, distance); - addCurve(curve, Location.EXTERIOR, Location.INTERIOR); - } - - private void addLineString(LineString line) - { - // a zero or negative width buffer of a line/point is empty - if (distance <= 0.0 && ! curveBuilder.getBufferParameters().isSingleSided()) - return; - Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates()); - Coordinate[] curve = curveBuilder.getLineCurve(coord, distance); - addCurve(curve, Location.EXTERIOR, Location.INTERIOR); - - // TESTING - //Coordinate[] curveTrim = BufferCurveLoopPruner.prune(curve); - //addCurve(curveTrim, Location.EXTERIOR, Location.INTERIOR); - } - - private void addPolygon(Polygon p) - { - double offsetDistance = distance; - int offsetSide = Position.LEFT; - if (distance < 0.0) { - offsetDistance = -distance; - offsetSide = Position.RIGHT; - } - - LinearRing shell = (LinearRing) p.getExteriorRing(); - Coordinate[] shellCoord = CoordinateArrays.removeRepeatedPoints(shell.getCoordinates()); - // optimization - don't bother computing buffer - // if the polygon would be completely eroded - if (distance < 0.0 && isErodedCompletely(shell, distance)) - return; - // don't attemtp to buffer a polygon with too few distinct vertices - if (distance <= 0.0 && shellCoord.length < 3) - return; - - addPolygonRing( - shellCoord, - offsetDistance, - offsetSide, - Location.EXTERIOR, - Location.INTERIOR); - - for (int i = 0; i < p.getNumInteriorRing(); i++) { - - LinearRing hole = (LinearRing) p.getInteriorRingN(i); - Coordinate[] holeCoord = CoordinateArrays.removeRepeatedPoints(hole.getCoordinates()); - - // optimization - don't bother computing buffer for this hole - // if the hole would be completely covered - if (distance > 0.0 && isErodedCompletely(hole, -distance)) - continue; - - // Holes are topologically labelled opposite to the shell, since - // the interior of the polygon lies on their opposite side - // (on the left, if the hole is oriented CCW) - addPolygonRing( - holeCoord, - offsetDistance, - Position.opposite(offsetSide), - Location.INTERIOR, - Location.EXTERIOR); - } - } - - /** - * Adds an offset curve for a polygon ring. - * The side and left and right topological location arguments - * assume that the ring is oriented CW. - * If the ring is in the opposite orientation, - * the left and right locations must be interchanged and the side flipped. - * - * @param coord the coordinates of the ring (must not contain repeated points) - * @param offsetDistance the distance at which to create the buffer - * @param side the side of the ring on which to construct the buffer line - * @param cwLeftLoc the location on the L side of the ring (if it is CW) - * @param cwRightLoc the location on the R side of the ring (if it is CW) - */ - private void addPolygonRing(Coordinate[] coord, double offsetDistance, int side, int cwLeftLoc, int cwRightLoc) - { - // don't bother adding ring if it is "flat" and will disappear in the output - if (offsetDistance == 0.0 && coord.length < LinearRing.MINIMUM_VALID_SIZE) - return; - - int leftLoc = cwLeftLoc; - int rightLoc = cwRightLoc; - if (coord.length >= LinearRing.MINIMUM_VALID_SIZE - && CGAlgorithms.isCCW(coord)) { - leftLoc = cwRightLoc; - rightLoc = cwLeftLoc; - side = Position.opposite(side); - } - Coordinate[] curve = curveBuilder.getRingCurve(coord, side, offsetDistance); - addCurve(curve, leftLoc, rightLoc); - } - - /** - * The ringCoord is assumed to contain no repeated points. - * It may be degenerate (i.e. contain only 1, 2, or 3 points). - * In this case it has no area, and hence has a minimum diameter of 0. - * - * @param ringCoord - * @param offsetDistance - * @return - */ - private boolean isErodedCompletely(LinearRing ring, double bufferDistance) - { - Coordinate[] ringCoord = ring.getCoordinates(); - double minDiam = 0.0; - // degenerate ring has no area - if (ringCoord.length < 4) - return bufferDistance < 0; - - // important test to eliminate inverted triangle bug - // also optimizes erosion test for triangles - if (ringCoord.length == 4) - return isTriangleErodedCompletely(ringCoord, bufferDistance); - - // if envelope is narrower than twice the buffer distance, ring is eroded - Envelope env = ring.getEnvelopeInternal(); - double envMinDimension = Math.min(env.getHeight(), env.getWidth()); - if (bufferDistance < 0.0 - && 2 * Math.abs(bufferDistance) > envMinDimension) - return true; - - return false; - /** - * The following is a heuristic test to determine whether an - * inside buffer will be eroded completely. - * It is based on the fact that the minimum diameter of the ring pointset - * provides an upper bound on the buffer distance which would erode the - * ring. - * If the buffer distance is less than the minimum diameter, the ring - * may still be eroded, but this will be determined by - * a full topological computation. - * - */ -//System.out.println(ring); -/* MD 7 Feb 2005 - there's an unknown bug in the MD code, so disable this for now - MinimumDiameter md = new MinimumDiameter(ring); - minDiam = md.getLength(); - //System.out.println(md.getDiameter()); - return minDiam < 2 * Math.abs(bufferDistance); - */ - } - - /** - * Tests whether a triangular ring would be eroded completely by the given - * buffer distance. - * This is a precise test. It uses the fact that the inner buffer of a - * triangle converges on the inCentre of the triangle (the point - * equidistant from all sides). If the buffer distance is greater than the - * distance of the inCentre from a side, the triangle will be eroded completely. - * - * This test is important, since it removes a problematic case where - * the buffer distance is slightly larger than the inCentre distance. - * In this case the triangle buffer curve "inverts" with incorrect topology, - * producing an incorrect hole in the buffer. - * - * @param triangleCoord - * @param bufferDistance - * @return - */ - private boolean isTriangleErodedCompletely( - Coordinate[] triangleCoord, - double bufferDistance) - { - Triangle tri = new Triangle(triangleCoord[0], triangleCoord[1], triangleCoord[2]); - Coordinate inCentre = tri.inCentre(); - double distToCentre = CGAlgorithms.distancePointLine(inCentre, tri.p0, tri.p1); - return distToCentre < Math.abs(bufferDistance); - } - - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java b/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java deleted file mode 100644 index 8b45f17553..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java +++ /dev/null @@ -1,678 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -import com.vividsolutions.jts.algorithm.Angle; -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.algorithm.HCoordinate; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.algorithm.NotRepresentableException; -import com.vividsolutions.jts.algorithm.RobustLineIntersector; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.LineSegment; -import com.vividsolutions.jts.geom.PrecisionModel; -import com.vividsolutions.jts.geomgraph.Position; -import com.vividsolutions.jts.util.Debug; - -/** - * Generates segments which form an offset curve. - * Supports all end cap and join options - * provided for buffering. - * This algorithm implements various heuristics to - * produce smoother, simpler curves which are - * still within a reasonable tolerance of the - * true curve. - * - * @author Martin Davis - * - */ -class OffsetSegmentGenerator -{ - - /** - * Factor which controls how close offset segments can be to - * skip adding a filler or mitre. - */ - private static final double OFFSET_SEGMENT_SEPARATION_FACTOR = 1.0E-3; - - /** - * Factor which controls how close curve vertices on inside turns can be to be snapped - */ - private static final double INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-3; - - /** - * Factor which controls how close curve vertices can be to be snapped - */ - private static final double CURVE_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-6; - - /** - * Factor which determines how short closing segs can be for round buffers - */ - private static final int MAX_CLOSING_SEG_LEN_FACTOR = 80; - - /** - * the max error of approximation (distance) between a quad segment and the true fillet curve - */ - private double maxCurveSegmentError = 0.0; - - /** - * The angle quantum with which to approximate a fillet curve - * (based on the input # of quadrant segments) - */ - private double filletAngleQuantum; - - /** - * The Closing Segment Length Factor controls how long - * "closing segments" are. Closing segments are added - * at the middle of inside corners to ensure a smoother - * boundary for the buffer offset curve. - * In some cases (particularly for round joins with default-or-better - * quantization) the closing segments can be made quite short. - * This substantially improves performance (due to fewer intersections being created). - * - * A closingSegFactor of 0 results in lines to the corner vertex - * A closingSegFactor of 1 results in lines halfway to the corner vertex - * A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex - * (this option is reasonable for the very common default situation of round joins - * and quadrantSegs >= 8) - */ - private int closingSegLengthFactor = 1; - - private OffsetSegmentString segList; - private double distance = 0.0; - private PrecisionModel precisionModel; - private BufferParameters bufParams; - private LineIntersector li; - - private Coordinate s0, s1, s2; - private LineSegment seg0 = new LineSegment(); - private LineSegment seg1 = new LineSegment(); - private LineSegment offset0 = new LineSegment(); - private LineSegment offset1 = new LineSegment(); - private int side = 0; - private boolean hasNarrowConcaveAngle = false; - - public OffsetSegmentGenerator(PrecisionModel precisionModel, - BufferParameters bufParams, double distance) { - this.precisionModel = precisionModel; - this.bufParams = bufParams; - - // compute intersections in full precision, to provide accuracy - // the points are rounded as they are inserted into the curve line - li = new RobustLineIntersector(); - filletAngleQuantum = Math.PI / 2.0 / bufParams.getQuadrantSegments(); - - /** - * Non-round joins cause issues with short closing segments, so don't use - * them. In any case, non-round joins only really make sense for relatively - * small buffer distances. - */ - if (bufParams.getQuadrantSegments() >= 8 - && bufParams.getJoinStyle() == BufferParameters.JOIN_ROUND) - closingSegLengthFactor = MAX_CLOSING_SEG_LEN_FACTOR; - init(distance); - } - - /** - * Tests whether the input has a narrow concave angle - * (relative to the offset distance). - * In this case the generated offset curve will contain self-intersections - * and heuristic closing segments. - * This is expected behaviour in the case of Buffer curves. - * For pure Offset Curves, - * the output needs to be further treated - * before it can be used. - * - * @return true if the input has a narrow concave angle - */ - public boolean hasNarrowConcaveAngle() - { - return hasNarrowConcaveAngle; - } - - private void init(double distance) - { - this.distance = distance; - maxCurveSegmentError = distance * (1 - Math.cos(filletAngleQuantum / 2.0)); - segList = new OffsetSegmentString(); - segList.setPrecisionModel(precisionModel); - /** - * Choose the min vertex separation as a small fraction of the offset distance. - */ - segList.setMinimumVertexDistance(distance * CURVE_VERTEX_SNAP_DISTANCE_FACTOR); - } - - - public void initSideSegments(Coordinate s1, Coordinate s2, int side) - { - this.s1 = s1; - this.s2 = s2; - this.side = side; - seg1.setCoordinates(s1, s2); - computeOffsetSegment(seg1, side, distance, offset1); - } - - public Coordinate[] getCoordinates() - { - Coordinate[] pts = segList.getCoordinates(); - return pts; - } - - public void closeRing() - { - segList.closeRing(); - } - - public void addSegments(Coordinate[] pt, boolean isForward) - { - segList.addPts(pt, isForward); - } - - public void addFirstSegment() - { - segList.addPt(offset1.p0); - } - - /** - * Add last offset point - */ - public void addLastSegment() - { - segList.addPt(offset1.p1); - } - - //private static double MAX_CLOSING_SEG_LEN = 3.0; - - public void addNextSegment(Coordinate p, boolean addStartPoint) - { - // s0-s1-s2 are the coordinates of the previous segment and the current one - s0 = s1; - s1 = s2; - s2 = p; - seg0.setCoordinates(s0, s1); - computeOffsetSegment(seg0, side, distance, offset0); - seg1.setCoordinates(s1, s2); - computeOffsetSegment(seg1, side, distance, offset1); - - // do nothing if points are equal - if (s1.equals(s2)) return; - - int orientation = CGAlgorithms.computeOrientation(s0, s1, s2); - boolean outsideTurn = - (orientation == CGAlgorithms.CLOCKWISE && side == Position.LEFT) - || (orientation == CGAlgorithms.COUNTERCLOCKWISE && side == Position.RIGHT); - - if (orientation == 0) { // lines are collinear - addCollinear(addStartPoint); - } - else if (outsideTurn) - { - addOutsideTurn(orientation, addStartPoint); - } - else { // inside turn - addInsideTurn(orientation, addStartPoint); - } - } - - private void addCollinear(boolean addStartPoint) - { - /** - * This test could probably be done more efficiently, - * but the situation of exact collinearity should be fairly rare. - */ - li.computeIntersection(s0, s1, s1, s2); - int numInt = li.getIntersectionNum(); - /** - * if numInt is < 2, the lines are parallel and in the same direction. In - * this case the point can be ignored, since the offset lines will also be - * parallel. - */ - if (numInt >= 2) { - /** - * segments are collinear but reversing. - * Add an "end-cap" fillet - * all the way around to other direction This case should ONLY happen - * for LineStrings, so the orientation is always CW. (Polygons can never - * have two consecutive segments which are parallel but reversed, - * because that would be a self intersection. - * - */ - if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL - || bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) { - if (addStartPoint) segList.addPt(offset0.p1); - segList.addPt(offset1.p0); - } - else { - addFillet(s1, offset0.p1, offset1.p0, CGAlgorithms.CLOCKWISE, distance); - } - } - } - - /** - * Adds the offset points for an outside (convex) turn - * - * @param orientation - * @param addStartPoint - */ - private void addOutsideTurn(int orientation, boolean addStartPoint) - { - /** - * Heuristic: If offset endpoints are very close together, - * just use one of them as the corner vertex. - * This avoids problems with computing mitre corners in the case - * where the two segments are almost parallel - * (which is hard to compute a robust intersection for). - */ - if (offset0.p1.distance(offset1.p0) < distance * OFFSET_SEGMENT_SEPARATION_FACTOR) { - segList.addPt(offset0.p1); - return; - } - - if (bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) { - addMitreJoin(s1, offset0, offset1, distance); - } - else if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL){ - addBevelJoin(offset0, offset1); - } - else { - // add a circular fillet connecting the endpoints of the offset segments - if (addStartPoint) segList.addPt(offset0.p1); - // TESTING - comment out to produce beveled joins - addFillet(s1, offset0.p1, offset1.p0, orientation, distance); - segList.addPt(offset1.p0); - } - } - - /** - * Adds the offset points for an inside (concave) turn. - * - * @param orientation - * @param addStartPoint - */ - private void addInsideTurn(int orientation, boolean addStartPoint) { - /** - * add intersection point of offset segments (if any) - */ - li.computeIntersection(offset0.p0, offset0.p1, offset1.p0, offset1.p1); - if (li.hasIntersection()) { - segList.addPt(li.getIntersection(0)); - } - else { - /** - * If no intersection is detected, - * it means the angle is so small and/or the offset so - * large that the offsets segments don't intersect. - * In this case we must - * add a "closing segment" to make sure the buffer curve is continuous, - * fairly smooth (e.g. no sharp reversals in direction) - * and tracks the buffer correctly around the corner. The curve connects - * the endpoints of the segment offsets to points - * which lie toward the centre point of the corner. - * The joining curve will not appear in the final buffer outline, since it - * is completely internal to the buffer polygon. - * - * In complex buffer cases the closing segment may cut across many other - * segments in the generated offset curve. In order to improve the - * performance of the noding, the closing segment should be kept as short as possible. - * (But not too short, since that would defeat its purpose). - * This is the purpose of the closingSegFactor heuristic value. - */ - - /** - * The intersection test above is vulnerable to robustness errors; i.e. it - * may be that the offsets should intersect very close to their endpoints, - * but aren't reported as such due to rounding. To handle this situation - * appropriately, we use the following test: If the offset points are very - * close, don't add closing segments but simply use one of the offset - * points - */ - hasNarrowConcaveAngle = true; - //System.out.println("NARROW ANGLE - distance = " + distance); - if (offset0.p1.distance(offset1.p0) < distance - * INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) { - segList.addPt(offset0.p1); - } else { - // add endpoint of this segment offset - segList.addPt(offset0.p1); - - /** - * Add "closing segment" of required length. - */ - if (closingSegLengthFactor > 0) { - Coordinate mid0 = new Coordinate((closingSegLengthFactor * offset0.p1.x + s1.x)/(closingSegLengthFactor + 1), - (closingSegLengthFactor*offset0.p1.y + s1.y)/(closingSegLengthFactor + 1)); - segList.addPt(mid0); - Coordinate mid1 = new Coordinate((closingSegLengthFactor*offset1.p0.x + s1.x)/(closingSegLengthFactor + 1), - (closingSegLengthFactor*offset1.p0.y + s1.y)/(closingSegLengthFactor + 1)); - segList.addPt(mid1); - } - else { - /** - * This branch is not expected to be used except for testing purposes. - * It is equivalent to the JTS 1.9 logic for closing segments - * (which results in very poor performance for large buffer distances) - */ - segList.addPt(s1); - } - - //*/ - // add start point of next segment offset - segList.addPt(offset1.p0); - } - } - } - - - /** - * Compute an offset segment for an input segment on a given side and at a given distance. - * The offset points are computed in full double precision, for accuracy. - * - * @param seg the segment to offset - * @param side the side of the segment ({@link Position}) the offset lies on - * @param distance the offset distance - * @param offset the points computed for the offset segment - */ - private void computeOffsetSegment(LineSegment seg, int side, double distance, LineSegment offset) - { - int sideSign = side == Position.LEFT ? 1 : -1; - double dx = seg.p1.x - seg.p0.x; - double dy = seg.p1.y - seg.p0.y; - double len = Math.sqrt(dx * dx + dy * dy); - // u is the vector that is the length of the offset, in the direction of the segment - double ux = sideSign * distance * dx / len; - double uy = sideSign * distance * dy / len; - offset.p0.x = seg.p0.x - uy; - offset.p0.y = seg.p0.y + ux; - offset.p1.x = seg.p1.x - uy; - offset.p1.y = seg.p1.y + ux; - } - - /** - * Add an end cap around point p1, terminating a line segment coming from p0 - */ - public void addLineEndCap(Coordinate p0, Coordinate p1) - { - LineSegment seg = new LineSegment(p0, p1); - - LineSegment offsetL = new LineSegment(); - computeOffsetSegment(seg, Position.LEFT, distance, offsetL); - LineSegment offsetR = new LineSegment(); - computeOffsetSegment(seg, Position.RIGHT, distance, offsetR); - - double dx = p1.x - p0.x; - double dy = p1.y - p0.y; - double angle = Math.atan2(dy, dx); - - switch (bufParams.getEndCapStyle()) { - case BufferParameters.CAP_ROUND: - // add offset seg points with a fillet between them - segList.addPt(offsetL.p1); - addFillet(p1, angle + Math.PI / 2, angle - Math.PI / 2, CGAlgorithms.CLOCKWISE, distance); - segList.addPt(offsetR.p1); - break; - case BufferParameters.CAP_FLAT: - // only offset segment points are added - segList.addPt(offsetL.p1); - segList.addPt(offsetR.p1); - break; - case BufferParameters.CAP_SQUARE: - // add a square defined by extensions of the offset segment endpoints - Coordinate squareCapSideOffset = new Coordinate(); - squareCapSideOffset.x = Math.abs(distance) * Math.cos(angle); - squareCapSideOffset.y = Math.abs(distance) * Math.sin(angle); - - Coordinate squareCapLOffset = new Coordinate( - offsetL.p1.x + squareCapSideOffset.x, - offsetL.p1.y + squareCapSideOffset.y); - Coordinate squareCapROffset = new Coordinate( - offsetR.p1.x + squareCapSideOffset.x, - offsetR.p1.y + squareCapSideOffset.y); - segList.addPt(squareCapLOffset); - segList.addPt(squareCapROffset); - break; - - } - } - /** - * Adds a mitre join connecting the two reflex offset segments. - * The mitre will be beveled if it exceeds the mitre ratio limit. - * - * @param offset0 the first offset segment - * @param offset1 the second offset segment - * @param distance the offset distance - */ - private void addMitreJoin(Coordinate p, - LineSegment offset0, - LineSegment offset1, - double distance) - { - boolean isMitreWithinLimit = true; - Coordinate intPt = null; - - /** - * This computation is unstable if the offset segments are nearly collinear. - * Howver, this situation should have been eliminated earlier by the check for - * whether the offset segment endpoints are almost coincident - */ - try { - intPt = HCoordinate.intersection(offset0.p0, - offset0.p1, offset1.p0, offset1.p1); - - double mitreRatio = distance <= 0.0 ? 1.0 - : intPt.distance(p) / Math.abs(distance); - - if (mitreRatio > bufParams.getMitreLimit()) - isMitreWithinLimit = false; - } - catch (NotRepresentableException ex) { - intPt = new Coordinate(0,0); - isMitreWithinLimit = false; - } - - if (isMitreWithinLimit) { - segList.addPt(intPt); - } - else { - addLimitedMitreJoin(offset0, offset1, distance, bufParams.getMitreLimit()); -// addBevelJoin(offset0, offset1); - } - } - - - /** - * Adds a limited mitre join connecting the two reflex offset segments. - * A limited mitre is a mitre which is beveled at the distance - * determined by the mitre ratio limit. - * - * @param offset0 the first offset segment - * @param offset1 the second offset segment - * @param distance the offset distance - * @param mitreLimit the mitre limit ratio - */ - private void addLimitedMitreJoin( - LineSegment offset0, - LineSegment offset1, - double distance, - double mitreLimit) - { - Coordinate basePt = seg0.p1; - - double ang0 = Angle.angle(basePt, seg0.p0); - double ang1 = Angle.angle(basePt, seg1.p1); - - // oriented angle between segments - double angDiff = Angle.angleBetweenOriented(seg0.p0, basePt, seg1.p1); - // half of the interior angle - double angDiffHalf = angDiff / 2; - - // angle for bisector of the interior angle between the segments - double midAng = Angle.normalize(ang0 + angDiffHalf); - // rotating this by PI gives the bisector of the reflex angle - double mitreMidAng = Angle.normalize(midAng + Math.PI); - - // the miterLimit determines the distance to the mitre bevel - double mitreDist = mitreLimit * distance; - // the bevel delta is the difference between the buffer distance - // and half of the length of the bevel segment - double bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf)); - double bevelHalfLen = distance - bevelDelta; - - // compute the midpoint of the bevel segment - double bevelMidX = basePt.x + mitreDist * Math.cos(mitreMidAng); - double bevelMidY = basePt.y + mitreDist * Math.sin(mitreMidAng); - Coordinate bevelMidPt = new Coordinate(bevelMidX, bevelMidY); - - // compute the mitre midline segment from the corner point to the bevel segment midpoint - LineSegment mitreMidLine = new LineSegment(basePt, bevelMidPt); - - // finally the bevel segment endpoints are computed as offsets from - // the mitre midline - Coordinate bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen); - Coordinate bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen); - - if (side == Position.LEFT) { - segList.addPt(bevelEndLeft); - segList.addPt(bevelEndRight); - } - else { - segList.addPt(bevelEndRight); - segList.addPt(bevelEndLeft); - } - } - - /** - * Adds a bevel join connecting the two offset segments - * around a reflex corner. - * - * @param offset0 the first offset segment - * @param offset1 the second offset segment - */ - private void addBevelJoin( - LineSegment offset0, - LineSegment offset1) - { - segList.addPt(offset0.p1); - segList.addPt(offset1.p0); - } - - - /** - * Add points for a circular fillet around a reflex corner. - * Adds the start and end points - * - * @param p base point of curve - * @param p0 start point of fillet curve - * @param p1 endpoint of fillet curve - * @param direction the orientation of the fillet - * @param radius the radius of the fillet - */ - private void addFillet(Coordinate p, Coordinate p0, Coordinate p1, int direction, double radius) - { - double dx0 = p0.x - p.x; - double dy0 = p0.y - p.y; - double startAngle = Math.atan2(dy0, dx0); - double dx1 = p1.x - p.x; - double dy1 = p1.y - p.y; - double endAngle = Math.atan2(dy1, dx1); - - if (direction == CGAlgorithms.CLOCKWISE) { - if (startAngle <= endAngle) startAngle += 2.0 * Math.PI; - } - else { // direction == COUNTERCLOCKWISE - if (startAngle >= endAngle) startAngle -= 2.0 * Math.PI; - } - segList.addPt(p0); - addFillet(p, startAngle, endAngle, direction, radius); - segList.addPt(p1); - } - - /** - * Adds points for a circular fillet arc - * between two specified angles. - * The start and end point for the fillet are not added - - * the caller must add them if required. - * - * @param direction is -1 for a CW angle, 1 for a CCW angle - * @param radius the radius of the fillet - */ - private void addFillet(Coordinate p, double startAngle, double endAngle, int direction, double radius) - { - int directionFactor = direction == CGAlgorithms.CLOCKWISE ? -1 : 1; - - double totalAngle = Math.abs(startAngle - endAngle); - int nSegs = (int) (totalAngle / filletAngleQuantum + 0.5); - - if (nSegs < 1) return; // no segments because angle is less than increment - nothing to do! - - double initAngle, currAngleInc; - - // choose angle increment so that each segment has equal length - initAngle = 0.0; - currAngleInc = totalAngle / nSegs; - - double currAngle = initAngle; - Coordinate pt = new Coordinate(); - while (currAngle < totalAngle) { - double angle = startAngle + directionFactor * currAngle; - pt.x = p.x + radius * Math.cos(angle); - pt.y = p.y + radius * Math.sin(angle); - segList.addPt(pt); - currAngle += currAngleInc; - } - } - - - /** - * Creates a CW circle around a point - */ - public void createCircle(Coordinate p) - { - // add start point - Coordinate pt = new Coordinate(p.x + distance, p.y); - segList.addPt(pt); - addFillet(p, 0.0, 2.0 * Math.PI, -1, distance); - segList.closeRing(); - } - - /** - * Creates a CW square around a point - */ - public void createSquare(Coordinate p) - { - segList.addPt(new Coordinate(p.x + distance, p.y + distance)); - segList.addPt(new Coordinate(p.x + distance, p.y - distance)); - segList.addPt(new Coordinate(p.x - distance, p.y - distance)); - segList.addPt(new Coordinate(p.x - distance, p.y + distance)); - segList.closeRing(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java b/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java deleted file mode 100644 index 07feb52c33..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * A dynamic list of the vertices in a constructed offset curve. - * Automatically removes adjacent vertices - * which are closer than a given tolerance. - * - * @author Martin Davis - * - */ -class OffsetSegmentString -{ - private static final Coordinate[] COORDINATE_ARRAY_TYPE = new Coordinate[0]; - - private ArrayList ptList; - private PrecisionModel precisionModel = null; - - /** - * The distance below which two adjacent points on the curve - * are considered to be coincident. - * This is chosen to be a small fraction of the offset distance. - */ - private double minimimVertexDistance = 0.0; - - public OffsetSegmentString() - { - ptList = new ArrayList(); - } - - public void setPrecisionModel(PrecisionModel precisionModel) - { - this.precisionModel = precisionModel; - } - - public void setMinimumVertexDistance(double minimimVertexDistance) - { - this.minimimVertexDistance = minimimVertexDistance; - } - - public void addPt(Coordinate pt) - { - Coordinate bufPt = new Coordinate(pt); - precisionModel.makePrecise(bufPt); - // don't add duplicate (or near-duplicate) points - if (isRedundant(bufPt)) - return; - ptList.add(bufPt); -//System.out.println(bufPt); - } - - public void addPts(Coordinate[] pt, boolean isForward) - { - if (isForward) { - for (int i = 0; i < pt.length; i++) { - addPt(pt[i]); - } - } - else { - for (int i = pt.length - 1; i >= 0; i--) { - addPt(pt[i]); - } - } - } - - /** - * Tests whether the given point is redundant - * relative to the previous - * point in the list (up to tolerance). - * - * @param pt - * @return true if the point is redundant - */ - private boolean isRedundant(Coordinate pt) - { - if (ptList.size() < 1) - return false; - Coordinate lastPt = (Coordinate) ptList.get(ptList.size() - 1); - double ptDist = pt.distance(lastPt); - if (ptDist < minimimVertexDistance) - return true; - return false; - } - - public void closeRing() - { - if (ptList.size() < 1) return; - Coordinate startPt = new Coordinate((Coordinate) ptList.get(0)); - Coordinate lastPt = (Coordinate) ptList.get(ptList.size() - 1); - Coordinate last2Pt = null; - if (ptList.size() >= 2) - last2Pt = (Coordinate) ptList.get(ptList.size() - 2); - if (startPt.equals(lastPt)) return; - ptList.add(startPt); - } - - public void reverse() - { - - } - - public Coordinate[] getCoordinates() - { - /* - // check that points are a ring - add the startpoint again if they are not - if (ptList.size() > 1) { - Coordinate start = (Coordinate) ptList.get(0); - Coordinate end = (Coordinate) ptList.get(ptList.size() - 1); - if (! start.equals(end) ) addPt(start); - } - */ - Coordinate[] coord = (Coordinate[]) ptList.toArray(COORDINATE_ARRAY_TYPE); - return coord; - } - - public String toString() - { - GeometryFactory fact = new GeometryFactory(); - LineString line = fact.createLineString(getCoordinates()); - return line.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java deleted file mode 100644 index cb147a7942..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java +++ /dev/null @@ -1,187 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.operation.overlay.*; -import com.vividsolutions.jts.util.*; - -/** - * A RightmostEdgeFinder find the DirectedEdge in a list which has the highest coordinate, - * and which is oriented L to R at that point. (I.e. the right side is on the RHS of the edge.) - * - * @version 1.7 - */ -class RightmostEdgeFinder { - - //private Coordinate extremeCoord; - private int minIndex = -1; - private Coordinate minCoord = null; - private DirectedEdge minDe = null; - private DirectedEdge orientedDe = null; - /** - * A RightmostEdgeFinder finds the DirectedEdge with the rightmost coordinate. - * The DirectedEdge returned is guaranteed to have the R of the world on its RHS. - */ - public RightmostEdgeFinder() - { - } - - public DirectedEdge getEdge() { return orientedDe; } - public Coordinate getCoordinate() { return minCoord; } - - public void findEdge(List dirEdgeList) - { - /** - * Check all forward DirectedEdges only. This is still general, - * because each edge has a forward DirectedEdge. - */ - for (Iterator i = dirEdgeList.iterator(); i.hasNext();) { - DirectedEdge de = (DirectedEdge) i.next(); - if (! de.isForward()) - continue; - checkForRightmostCoordinate(de); - } - - /** - * If the rightmost point is a node, we need to identify which of - * the incident edges is rightmost. - */ - Assert.isTrue(minIndex != 0 || minCoord.equals(minDe.getCoordinate()) , "inconsistency in rightmost processing"); - if (minIndex == 0 ) { - findRightmostEdgeAtNode(); - } - else { - findRightmostEdgeAtVertex(); - } - /** - * now check that the extreme side is the R side. - * If not, use the sym instead. - */ - orientedDe = minDe; - int rightmostSide = getRightmostSide(minDe, minIndex); - if (rightmostSide == Position.LEFT) { - orientedDe = minDe.getSym(); - } - } - private void findRightmostEdgeAtNode() - { - Node node = minDe.getNode(); - DirectedEdgeStar star = (DirectedEdgeStar) node.getEdges(); - minDe = star.getRightmostEdge(); - // the DirectedEdge returned by the previous call is not - // necessarily in the forward direction. Use the sym edge if it isn't. - if (! minDe.isForward()) { - minDe = minDe.getSym(); - minIndex = minDe.getEdge().getCoordinates().length - 1; - } - } - private void findRightmostEdgeAtVertex() - { - /** - * The rightmost point is an interior vertex, so it has a segment on either side of it. - * If these segments are both above or below the rightmost point, we need to - * determine their relative orientation to decide which is rightmost. - */ - Coordinate[] pts = minDe.getEdge().getCoordinates(); - Assert.isTrue(minIndex > 0 && minIndex < pts.length, "rightmost point expected to be interior vertex of edge"); - Coordinate pPrev = pts[minIndex - 1]; - Coordinate pNext = pts[minIndex + 1]; - int orientation = CGAlgorithms.computeOrientation(minCoord, pNext, pPrev); - boolean usePrev = false; - // both segments are below min point - if (pPrev.y < minCoord.y && pNext.y < minCoord.y - && orientation == CGAlgorithms.COUNTERCLOCKWISE) { - usePrev = true; - } - else if (pPrev.y > minCoord.y && pNext.y > minCoord.y - && orientation == CGAlgorithms.CLOCKWISE) { - usePrev = true; - } - // if both segments are on the same side, do nothing - either is safe - // to select as a rightmost segment - if (usePrev) { - minIndex = minIndex - 1; - } - } - private void checkForRightmostCoordinate(DirectedEdge de) - { - Coordinate[] coord = de.getEdge().getCoordinates(); - for (int i = 0; i < coord.length - 1; i++) { - // only check vertices which are the start or end point of a non-horizontal segment - // MD 19 Sep 03 - NO! we can test all vertices, since the rightmost must have a non-horiz segment adjacent to it - if (minCoord == null || coord[i].x > minCoord.x ) { - minDe = de; - minIndex = i; - minCoord = coord[i]; - } - //} - } - } - - private int getRightmostSide(DirectedEdge de, int index) - { - int side = getRightmostSideOfSegment(de, index); - if (side < 0) - side = getRightmostSideOfSegment(de, index - 1); - if (side < 0) { - // reaching here can indicate that segment is horizontal - //Assert.shouldNeverReachHere("problem with finding rightmost side of segment at " + de.getCoordinate()); - // testing only - minCoord = null; - checkForRightmostCoordinate(de); - } - return side; - } - - private int getRightmostSideOfSegment(DirectedEdge de, int i) - { - Edge e = de.getEdge(); - Coordinate coord[] = e.getCoordinates(); - - if (i < 0 || i + 1 >= coord.length) return -1; - if (coord[i].y == coord[i + 1].y) return -1; // indicates edge is parallel to x-axis - - int pos = Position.LEFT; - if (coord[i].y < coord[i + 1].y) pos = Position.RIGHT; - return pos; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java b/src/main/java/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java deleted file mode 100644 index 2ab435b38a..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java +++ /dev/null @@ -1,258 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.algorithm.*; - -/** - * Locates a subgraph inside a set of subgraphs, - * in order to determine the outside depth of the subgraph. - * The input subgraphs are assumed to have had depths - * already calculated for their edges. - * - * @version 1.7 - */ -class SubgraphDepthLocater -{ - private Collection subgraphs; - private LineSegment seg = new LineSegment(); - private CGAlgorithms cga = new CGAlgorithms(); - - public SubgraphDepthLocater(List subgraphs) - { - this.subgraphs = subgraphs; - } - - public int getDepth(Coordinate p) - { - List stabbedSegments = findStabbedSegments(p); - // if no segments on stabbing line subgraph must be outside all others. - if (stabbedSegments.size() == 0) - return 0; - DepthSegment ds = (DepthSegment) Collections.min(stabbedSegments); - return ds.leftDepth; - } - - /** - * Finds all non-horizontal segments intersecting the stabbing line. - * The stabbing line is the ray to the right of stabbingRayLeftPt. - * - * @param stabbingRayLeftPt the left-hand origin of the stabbing line - * @return a List of {@link DepthSegments} intersecting the stabbing line - */ - private List findStabbedSegments(Coordinate stabbingRayLeftPt) - { - List stabbedSegments = new ArrayList(); - for (Iterator i = subgraphs.iterator(); i.hasNext(); ) { - BufferSubgraph bsg = (BufferSubgraph) i.next(); - - // optimization - don't bother checking subgraphs which the ray does not intersect - Envelope env = bsg.getEnvelope(); - if (stabbingRayLeftPt.y < env.getMinY() - || stabbingRayLeftPt.y > env.getMaxY()) - continue; - - findStabbedSegments(stabbingRayLeftPt, bsg.getDirectedEdges(), stabbedSegments); - } - return stabbedSegments; - } - - /** - * Finds all non-horizontal segments intersecting the stabbing line - * in the list of dirEdges. - * The stabbing line is the ray to the right of stabbingRayLeftPt. - * - * @param stabbingRayLeftPt the left-hand origin of the stabbing line - * @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line - */ - private void findStabbedSegments(Coordinate stabbingRayLeftPt, - List dirEdges, - List stabbedSegments) - { - /** - * Check all forward DirectedEdges only. This is still general, - * because each Edge has a forward DirectedEdge. - */ - for (Iterator i = dirEdges.iterator(); i.hasNext();) { - DirectedEdge de = (DirectedEdge) i.next(); - if (! de.isForward()) - continue; - findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments); - } - } - - /** - * Finds all non-horizontal segments intersecting the stabbing line - * in the input dirEdge. - * The stabbing line is the ray to the right of stabbingRayLeftPt. - * - * @param stabbingRayLeftPt the left-hand origin of the stabbing line - * @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line - */ - private void findStabbedSegments(Coordinate stabbingRayLeftPt, - DirectedEdge dirEdge, - List stabbedSegments) - { - Coordinate[] pts = dirEdge.getEdge().getCoordinates(); - for (int i = 0; i < pts.length - 1; i++) { - seg.p0 = pts[i]; - seg.p1 = pts[i + 1]; - // ensure segment always points upwards - if (seg.p0.y > seg.p1.y) - seg.reverse(); - - // skip segment if it is left of the stabbing line - double maxx = Math.max(seg.p0.x, seg.p1.x); - if (maxx < stabbingRayLeftPt.x) - continue; - - // skip horizontal segments (there will be a non-horizontal one carrying the same depth info - if (seg.isHorizontal()) - continue; - - // skip if segment is above or below stabbing line - if (stabbingRayLeftPt.y < seg.p0.y || stabbingRayLeftPt.y > seg.p1.y) - continue; - - // skip if stabbing ray is right of the segment - if (CGAlgorithms.computeOrientation(seg.p0, seg.p1, stabbingRayLeftPt) - == CGAlgorithms.RIGHT) - continue; - - // stabbing line cuts this segment, so record it - int depth = dirEdge.getDepth(Position.LEFT); - // if segment direction was flipped, use RHS depth instead - if (! seg.p0.equals(pts[i])) - depth = dirEdge.getDepth(Position.RIGHT); - DepthSegment ds = new DepthSegment(seg, depth); - stabbedSegments.add(ds); - } - } - - - /** - * A segment from a directed edge which has been assigned a depth value - * for its sides. - */ - static class DepthSegment - implements Comparable - { - private LineSegment upwardSeg; - private int leftDepth; - - public DepthSegment(LineSegment seg, int depth) - { - // input seg is assumed to be normalized - upwardSeg = new LineSegment(seg); - //upwardSeg.normalize(); - this.leftDepth = depth; - } - /** - * Defines a comparison operation on DepthSegments - * which orders them left to right. - * Assumes the segments are normalized. - *

                    - * The definition of the ordering is: - *

                      - *
                    • -1 : if DS1.seg is left of or below DS2.seg (DS1 < DS2) - *
                    • 1 : if DS1.seg is right of or above DS2.seg (DS1 > DS2) - *
                    • 0 : if the segments are identical - *
                    - * - * KNOWN BUGS: - *
                      - *
                    • The logic does not obey the {@link Comparator.compareTo} contract. - * This is acceptable for the intended usage, but may cause problems if used with some - * utilities in the Java standard library (e.g. {@link Collections.sort()}. - *
                    - * - * @param obj a DepthSegment - * @return the comparison value - */ - public int compareTo(Object obj) - { - DepthSegment other = (DepthSegment) obj; - - // fast check if segments are trivially ordered along X - if (upwardSeg.minX() >= other.upwardSeg.maxX()) return 1; - if (upwardSeg.maxX() <= other.upwardSeg.minX()) return -1; - - /** - * try and compute a determinate orientation for the segments. - * Test returns 1 if other is left of this (i.e. this > other) - */ - int orientIndex = upwardSeg.orientationIndex(other.upwardSeg); - if (orientIndex != 0) return orientIndex; - - /** - * If comparison between this and other is indeterminate, - * try the opposite call order. - * The sign of the result needs to be flipped. - */ - orientIndex = -1 * other.upwardSeg.orientationIndex(upwardSeg); - if (orientIndex != 0) return orientIndex; - - // otherwise, use standard lexocographic segment ordering - return upwardSeg.compareTo(other.upwardSeg); - } - - /** - * Compare two collinear segments for left-most ordering. - * If segs are vertical, use vertical ordering for comparison. - * If segs are equal, return 0. - * Segments are assumed to be directed so that the second coordinate is >= to the first - * (e.g. up and to the right). - * - * @param seg0 a segment to compare - * @param seg1 a segment to compare - * @return - */ - private int compareX(LineSegment seg0, LineSegment seg1) - { - int compare0 = seg0.p0.compareTo(seg1.p0); - if (compare0 != 0) - return compare0; - return seg0.p1.compareTo(seg1.p1); - - } - - public String toString() - { - return upwardSeg.toString(); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferCurveMaximumDistanceFinder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferCurveMaximumDistanceFinder.java deleted file mode 100644 index b379855f1a..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferCurveMaximumDistanceFinder.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer.validate; - -import com.vividsolutions.jts.geom.*; - -/** - * Finds the approximate maximum distance from a buffer curve to - * the originating geometry. - * This is similar to the Discrete Oriented Hausdorff distance - * from the buffer curve to the input. - *

                    - * The approximate maximum distance is determined by testing - * all vertices in the buffer curve, as well - * as midpoints of the curve segments. - * Due to the way buffer curves are constructed, this - * should be a very close approximation. - * - * @author mbdavis - * - */ -public class BufferCurveMaximumDistanceFinder -{ - private Geometry inputGeom; - private PointPairDistance maxPtDist = new PointPairDistance(); - - public BufferCurveMaximumDistanceFinder(Geometry inputGeom) - { - this.inputGeom = inputGeom; - } - - public double findDistance(Geometry bufferCurve) - { - computeMaxVertexDistance(bufferCurve); - computeMaxMidpointDistance(bufferCurve); - return maxPtDist.getDistance(); - } - - public PointPairDistance getDistancePoints() - { - return maxPtDist; - } - private void computeMaxVertexDistance(Geometry curve) - { - MaxPointDistanceFilter distFilter = new MaxPointDistanceFilter(inputGeom); - curve.apply(distFilter); - maxPtDist.setMaximum(distFilter.getMaxPointDistance()); - } - - private void computeMaxMidpointDistance(Geometry curve) - { - MaxMidpointDistanceFilter distFilter = new MaxMidpointDistanceFilter(inputGeom); - curve.apply(distFilter); - maxPtDist.setMaximum(distFilter.getMaxPointDistance()); - } - - public static class MaxPointDistanceFilter implements CoordinateFilter { - private PointPairDistance maxPtDist = new PointPairDistance(); - private PointPairDistance minPtDist = new PointPairDistance(); - private Geometry geom; - - public MaxPointDistanceFilter(Geometry geom) { - this.geom = geom; - } - - public void filter(Coordinate pt) { - minPtDist.initialize(); - DistanceToPointFinder.computeDistance(geom, pt, minPtDist); - maxPtDist.setMaximum(minPtDist); - } - - public PointPairDistance getMaxPointDistance() { - return maxPtDist; - } - } - - public static class MaxMidpointDistanceFilter - implements CoordinateSequenceFilter - { - private PointPairDistance maxPtDist = new PointPairDistance(); - private PointPairDistance minPtDist = new PointPairDistance(); - private Geometry geom; - - public MaxMidpointDistanceFilter(Geometry geom) { - this.geom = geom; - } - - public void filter(CoordinateSequence seq, int index) - { - if (index == 0) - return; - - Coordinate p0 = seq.getCoordinate(index - 1); - Coordinate p1 = seq.getCoordinate(index); - Coordinate midPt = new Coordinate( - (p0.x + p1.x)/2, - (p0.y + p1.y)/2); - - minPtDist.initialize(); - DistanceToPointFinder.computeDistance(geom, midPt, minPtDist); - maxPtDist.setMaximum(minPtDist); - } - - public boolean isGeometryChanged() { return false; } - - public boolean isDone() { return false; } - - public PointPairDistance getMaxPointDistance() { - return maxPtDist; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java b/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java deleted file mode 100644 index d64ba01610..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer.validate; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.operation.distance.*; -import com.vividsolutions.jts.algorithm.distance.*; - -/** - * Validates that a given buffer curve lies an appropriate distance - * from the input generating it. - * Useful only for round buffers (cap and join). - * Can be used for either positive or negative distances. - *

                    - * This is a heuristic test, and may return false positive results - * (I.e. it may fail to detect an invalid result.) - * It should never return a false negative result, however - * (I.e. it should never report a valid result as invalid.) - * - * @author mbdavis - * - */ -public class BufferDistanceValidator -{ - private static boolean VERBOSE = false; - /** - * Maximum allowable fraction of buffer distance the - * actual distance can differ by. - * 1% sometimes causes an error - 1.2% should be safe. - */ - private static final double MAX_DISTANCE_DIFF_FRAC = .012; - - private Geometry input; - private double bufDistance; - private Geometry result; - - private double minValidDistance; - private double maxValidDistance; - - private double minDistanceFound; - private double maxDistanceFound; - - private boolean isValid = true; - private String errMsg = null; - private Coordinate errorLocation = null; - private Geometry errorIndicator = null; - - public BufferDistanceValidator(Geometry input, double bufDistance, Geometry result) - { - this.input = input; - this.bufDistance = bufDistance; - this.result = result; - } - - public boolean isValid() - { - double posDistance = Math.abs(bufDistance); - double distDelta = MAX_DISTANCE_DIFF_FRAC * posDistance; - minValidDistance = posDistance - distDelta; - maxValidDistance = posDistance + distDelta; - - // can't use this test if either is empty - if (input.isEmpty() || result.isEmpty()) - return true; - - if (bufDistance > 0.0) { - checkPositiveValid(); - } - else { - checkNegativeValid(); - } - if (VERBOSE) { - System.out.println("Min Dist= " + minDistanceFound + " err= " - + (1.0 - minDistanceFound / bufDistance) - + " Max Dist= " + maxDistanceFound + " err= " - + (maxDistanceFound / bufDistance - 1.0) - ); - } - return isValid; - } - - public String getErrorMessage() - { - return errMsg; - } - - public Coordinate getErrorLocation() - { - return errorLocation; - } - - /** - * Gets a geometry which indicates the location and nature of a validation failure. - *

                    - * The indicator is a line segment showing the location and size - * of the distance discrepancy. - * - * @return a geometric error indicator - * or null if no error was found - */ - public Geometry getErrorIndicator() - { - return errorIndicator; - } - - private void checkPositiveValid() - { - Geometry bufCurve = result.getBoundary(); - checkMinimumDistance(input, bufCurve, minValidDistance); - if (! isValid) return; - - checkMaximumDistance(input, bufCurve, maxValidDistance); - } - - private void checkNegativeValid() - { - // Assert: only polygonal inputs can be checked for negative buffers - - // MD - could generalize this to handle GCs too - if (! (input instanceof Polygon - || input instanceof MultiPolygon - || input instanceof GeometryCollection - )) { - return; - } - Geometry inputCurve = getPolygonLines(input); - checkMinimumDistance(inputCurve, result, minValidDistance); - if (! isValid) return; - - checkMaximumDistance(inputCurve, result, maxValidDistance); - } - - private Geometry getPolygonLines(Geometry g) - { - List lines = new ArrayList(); - LinearComponentExtracter lineExtracter = new LinearComponentExtracter(lines); - List polys = PolygonExtracter.getPolygons(g); - for (Iterator i = polys.iterator(); i.hasNext(); ) { - Polygon poly = (Polygon) i.next(); - poly.apply(lineExtracter); - } - return g.getFactory().buildGeometry(lines); - } - - /** - * Checks that two geometries are at least a minumum distance apart. - * - * @param g1 a geometry - * @param g2 a geometry - * @param minDist the minimum distance the geometries should be separated by - */ - private void checkMinimumDistance(Geometry g1, Geometry g2, double minDist) - { - DistanceOp distOp = new DistanceOp(g1, g2, minDist); - minDistanceFound = distOp.distance(); - - - if (minDistanceFound < minDist) { - isValid = false; - Coordinate[] pts = distOp.nearestPoints(); - errorLocation = distOp.nearestPoints()[1]; - errorIndicator = g1.getFactory().createLineString(pts); - errMsg = "Distance between buffer curve and input is too small " - + "(" + minDistanceFound - + " at " + WKTWriter.toLineString(pts[0], pts[1]) +" )"; - } - } - - /** - * Checks that the furthest distance from the buffer curve to the input - * is less than the given maximum distance. - * This uses the Oriented Hausdorff distance metric. - * It corresponds to finding - * the point on the buffer curve which is furthest from some point on the input. - * - * @param input a geometry - * @param bufCurve a geometry - * @param maxDist the maximum distance that a buffer result can be from the input - */ - private void checkMaximumDistance(Geometry input, Geometry bufCurve, double maxDist) - { -// BufferCurveMaximumDistanceFinder maxDistFinder = new BufferCurveMaximumDistanceFinder(input); -// maxDistanceFound = maxDistFinder.findDistance(bufCurve); - - DiscreteHausdorffDistance haus = new DiscreteHausdorffDistance(bufCurve, input); - haus.setDensifyFraction(0.25); - maxDistanceFound = haus.orientedDistance(); - - if (maxDistanceFound > maxDist) { - isValid = false; - Coordinate[] pts = haus.getCoordinates(); - errorLocation = pts[1]; - errorIndicator = input.getFactory().createLineString(pts); - errMsg = "Distance between buffer curve and input is too large " - + "(" + maxDistanceFound - + " at " + WKTWriter.toLineString(pts[0], pts[1]) +")"; - } - } - - /* - private void OLDcheckMaximumDistance(Geometry input, Geometry bufCurve, double maxDist) - { - BufferCurveMaximumDistanceFinder maxDistFinder = new BufferCurveMaximumDistanceFinder(input); - maxDistanceFound = maxDistFinder.findDistance(bufCurve); - - - if (maxDistanceFound > maxDist) { - isValid = false; - PointPairDistance ptPairDist = maxDistFinder.getDistancePoints(); - errorLocation = ptPairDist.getCoordinate(1); - errMsg = "Distance between buffer curve and input is too large " - + "(" + ptPairDist.getDistance() - + " at " + ptPairDist.toString() +")"; - } - } - */ - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java b/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java deleted file mode 100644 index 7daddbb818..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer.validate; - -import com.vividsolutions.jts.geom.*; - -/** - * Validates that the result of a buffer operation - * is geometrically correct, within a computed tolerance. - *

                    - * This is a heuristic test, and may return false positive results - * (I.e. it may fail to detect an invalid result.) - * It should never return a false negative result, however - * (I.e. it should never report a valid result as invalid.) - *

                    - * This test may be (much) more expensive than the original - * buffer computation. - * - * @author Martin Davis - */ -public class BufferResultValidator -{ - private static boolean VERBOSE = false; - - /** - * Maximum allowable fraction of buffer distance the - * actual distance can differ by. - * 1% sometimes causes an error - 1.2% should be safe. - */ - private static final double MAX_ENV_DIFF_FRAC = .012; - - public static boolean isValid(Geometry g, double distance, Geometry result) - { - BufferResultValidator validator = new BufferResultValidator(g, distance, result); - if (validator.isValid()) - return true; - return false; - } - - /** - * Checks whether the geometry buffer is valid, - * and returns an error message if not. - * - * @param g - * @param distance - * @param result - * @return an appropriate error message - * or null if the buffer is valid - */ - public static String isValidMsg(Geometry g, double distance, Geometry result) - { - BufferResultValidator validator = new BufferResultValidator(g, distance, result); - if (! validator.isValid()) - return validator.getErrorMessage(); - return null; - } - - private Geometry input; - private double distance; - private Geometry result; - private boolean isValid = true; - private String errorMsg = null; - private Coordinate errorLocation = null; - private Geometry errorIndicator = null; - - public BufferResultValidator(Geometry input, double distance, Geometry result) - { - this.input = input; - this.distance = distance; - this.result = result; - } - - public boolean isValid() - { - checkPolygonal(); - if (! isValid) return isValid; - checkExpectedEmpty(); - if (! isValid) return isValid; - checkEnvelope(); - if (! isValid) return isValid; - checkArea(); - if (! isValid) return isValid; - checkDistance(); - return isValid; - } - - public String getErrorMessage() - { - return errorMsg; - } - - public Coordinate getErrorLocation() - { - return errorLocation; - } - - /** - * Gets a geometry which indicates the location and nature of a validation failure. - *

                    - * If the failure is due to the buffer curve being too far or too close - * to the input, the indicator is a line segment showing the location and size - * of the discrepancy. - * - * @return a geometric error indicator - * or null if no error was found - */ - public Geometry getErrorIndicator() - { - return errorIndicator; - } - - private void report(String checkName) - { - if (! VERBOSE) return; - System.out.println("Check " + checkName + ": " - + (isValid ? "passed" : "FAILED")); - } - - private void checkPolygonal() - { - if (! (result instanceof Polygon - || result instanceof MultiPolygon)) - isValid = false; - errorMsg = "Result is not polygonal"; - errorIndicator = result; - report("Polygonal"); - } - - private void checkExpectedEmpty() - { - // can't check areal features - if (input.getDimension() >= 2) return; - // can't check positive distances - if (distance > 0.0) return; - - // at this point can expect an empty result - if (! result.isEmpty()) { - isValid = false; - errorMsg = "Result is non-empty"; - errorIndicator = result; - } - report("ExpectedEmpty"); - } - - private void checkEnvelope() - { - if (distance < 0.0) return; - - double padding = distance * MAX_ENV_DIFF_FRAC; - if (padding == 0.0) padding = 0.001; - - Envelope expectedEnv = new Envelope(input.getEnvelopeInternal()); - expectedEnv.expandBy(distance); - - Envelope bufEnv = new Envelope(result.getEnvelopeInternal()); - bufEnv.expandBy(padding); - - if (! bufEnv.contains(expectedEnv)) { - isValid = false; - errorMsg = "Buffer envelope is incorrect"; - errorIndicator = input.getFactory().toGeometry(bufEnv); - } - report("Envelope"); - } - - private void checkArea() - { - double inputArea = input.getArea(); - double resultArea = result.getArea(); - - if (distance > 0.0 - && inputArea > resultArea) { - isValid = false; - errorMsg = "Area of positive buffer is smaller than input"; - errorIndicator = result; - } - if (distance < 0.0 - && inputArea < resultArea) { - isValid = false; - errorMsg = "Area of negative buffer is larger than input"; - errorIndicator = result; - } - report("Area"); - } - - private void checkDistance() - { - BufferDistanceValidator distValid = new BufferDistanceValidator(input, distance, result); - if (! distValid.isValid()) { - isValid = false; - errorMsg = distValid.getErrorMessage(); - errorLocation = distValid.getErrorLocation(); - errorIndicator = distValid.getErrorIndicator(); - } - report("Distance"); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/DistanceToPointFinder.java b/src/main/java/com/vividsolutions/jts/operation/buffer/validate/DistanceToPointFinder.java deleted file mode 100644 index ea0dd59d24..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/DistanceToPointFinder.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer.validate; - -import com.vividsolutions.jts.geom.*; - -/** - * Computes the Euclidean distance (L2 metric) from a Point to a Geometry. - * Also computes two points which are separated by the distance. - */ -public class DistanceToPointFinder { - - public DistanceToPointFinder() { - } - - public static void computeDistance(Geometry geom, Coordinate pt, PointPairDistance ptDist) - { - if (geom instanceof LineString) { - computeDistance((LineString) geom, pt, ptDist); - } - else if (geom instanceof Polygon) { - computeDistance((Polygon) geom, pt, ptDist); - } - else if (geom instanceof GeometryCollection) { - GeometryCollection gc = (GeometryCollection) geom; - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - computeDistance(g, pt, ptDist); - } - } - else { // assume geom is Point - ptDist.setMinimum(geom.getCoordinate(), pt); - } - } - public static void computeDistance(LineString line, Coordinate pt, PointPairDistance ptDist) - { - Coordinate[] coords = line.getCoordinates(); - LineSegment tempSegment = new LineSegment(); - for (int i = 0; i < coords.length - 1; i++) { - tempSegment.setCoordinates(coords[i], coords[i + 1]); - // this is somewhat inefficient - could do better - Coordinate closestPt = tempSegment.closestPoint(pt); - ptDist.setMinimum(closestPt, pt); - } - } - - public static void computeDistance(LineSegment segment, Coordinate pt, PointPairDistance ptDist) - { - Coordinate closestPt = segment.closestPoint(pt); - ptDist.setMinimum(closestPt, pt); - } - - public static void computeDistance(Polygon poly, Coordinate pt, PointPairDistance ptDist) - { - computeDistance(poly.getExteriorRing(), pt, ptDist); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - computeDistance(poly.getInteriorRingN(i), pt, ptDist); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/PointPairDistance.java b/src/main/java/com/vividsolutions/jts/operation/buffer/validate/PointPairDistance.java deleted file mode 100644 index acdb9c7dc9..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/buffer/validate/PointPairDistance.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.buffer.validate; - -import com.vividsolutions.jts.geom.*; - -/** - * Contains a pair of points and the distance between them. - * Provides methods to update with a new point pair with - * either maximum or minimum distance. - */ -public class PointPairDistance { - - private Coordinate[] pt = { new Coordinate(), new Coordinate() }; - private double distance = Double.NaN; - private boolean isNull = true; - - public PointPairDistance() - { - } - - public void initialize() { isNull = true; } - - public void initialize(Coordinate p0, Coordinate p1) - { - pt[0].setCoordinate(p0); - pt[1].setCoordinate(p1); - distance = p0.distance(p1); - isNull = false; - } - - /** - * Initializes the points, avoiding recomputing the distance. - * @param p0 - * @param p1 - * @param distance the distance between p0 and p1 - */ - private void initialize(Coordinate p0, Coordinate p1, double distance) - { - pt[0].setCoordinate(p0); - pt[1].setCoordinate(p1); - this.distance = distance; - isNull = false; - } - - public double getDistance() { return distance; } - - public Coordinate[] getCoordinates() { return pt; } - - public Coordinate getCoordinate(int i) { return pt[i]; } - - public void setMaximum(PointPairDistance ptDist) - { - setMaximum(ptDist.pt[0], ptDist.pt[1]); - } - - public void setMaximum(Coordinate p0, Coordinate p1) - { - if (isNull) { - initialize(p0, p1); - return; - } - double dist = p0.distance(p1); - if (dist > distance) - initialize(p0, p1, dist); - } - - public void setMinimum(PointPairDistance ptDist) - { - setMinimum(ptDist.pt[0], ptDist.pt[1]); - } - - public void setMinimum(Coordinate p0, Coordinate p1) - { - if (isNull) { - initialize(p0, p1); - return; - } - double dist = p0.distance(p1); - if (dist < distance) - initialize(p0, p1, dist); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java b/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java deleted file mode 100644 index 073e771f27..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java +++ /dev/null @@ -1,80 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.distance; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * A ConnectedElementPointFilter extracts a single point - * from each connected element in a Geometry - * (e.g. a polygon, linestring or point) - * and returns them in a list. The elements of the list are - * {@link com.vividsolutions.jts.operation.distance.GeometryLocation}s. - * - * @version 1.7 - */ -public class ConnectedElementLocationFilter - implements GeometryFilter -{ - - /** - * Returns a list containing a point from each Polygon, LineString, and Point - * found inside the specified geometry. Thus, if the specified geometry is - * not a GeometryCollection, an empty list will be returned. The elements of the list - * are {@link com.vividsolutions.jts.operation.distance.GeometryLocation}s. - */ - public static List getLocations(Geometry geom) - { - List locations = new ArrayList(); - geom.apply(new ConnectedElementLocationFilter(locations)); - return locations; - } - - private List locations; - - ConnectedElementLocationFilter(List locations) - { - this.locations = locations; - } - - public void filter(Geometry geom) - { - if (geom instanceof Point - || geom instanceof LineString - || geom instanceof Polygon ) - locations.add(new GeometryLocation(geom, 0, geom.getCoordinate())); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java b/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java deleted file mode 100644 index 70c127e6be..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java +++ /dev/null @@ -1,78 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.distance; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Extracts a single point - * from each connected element in a Geometry - * (e.g. a polygon, linestring or point) - * and returns them in a list - * - * @version 1.7 - */ -public class ConnectedElementPointFilter - implements GeometryFilter -{ - - /** - * Returns a list containing a Coordinate from each Polygon, LineString, and Point - * found inside the specified geometry. Thus, if the specified geometry is - * not a GeometryCollection, an empty list will be returned. - */ - public static List getCoordinates(Geometry geom) - { - List pts = new ArrayList(); - geom.apply(new ConnectedElementPointFilter(pts)); - return pts; - } - - private List pts; - - ConnectedElementPointFilter(List pts) - { - this.pts = pts; - } - - public void filter(Geometry geom) - { - if (geom instanceof Point - || geom instanceof LineString - || geom instanceof Polygon ) - pts.add(geom.getCoordinate()); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/DistanceOp.java b/src/main/java/com/vividsolutions/jts/operation/distance/DistanceOp.java deleted file mode 100644 index fec64106f3..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/DistanceOp.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.distance; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.algorithm.*; - -/** - * Find two points on two {@link Geometry}s which lie - * within a given distance, or else are the nearest points - * on the geometries (in which case this also - * provides the distance between the geometries). - *

                    - * The distance computation also finds a pair of points in the input geometries - * which have the minimum distance between them. - * If a point lies in the interior of a line segment, - * the coordinate computed is a close - * approximation to the exact point. - *

                    - * The algorithms used are straightforward O(n^2) - * comparisons. This worst-case performance could be improved on - * by using Voronoi techniques or spatial indexes. - * - * @version 1.7 - */ -public class DistanceOp -{ - /** - * Compute the distance between the nearest points of two geometries. - * @param g0 a {@link Geometry} - * @param g1 another {@link Geometry} - * @return the distance between the geometries - */ - public static double distance(Geometry g0, Geometry g1) - { - DistanceOp distOp = new DistanceOp(g0, g1); - return distOp.distance(); - } - - /** - * Test whether two geometries lie within a given distance of each other. - * @param g0 a {@link Geometry} - * @param g1 another {@link Geometry} - * @param distance the distance to test - * @return true if g0.distance(g1) <= distance - */ - public static boolean isWithinDistance(Geometry g0, Geometry g1, double distance) - { - DistanceOp distOp = new DistanceOp(g0, g1, distance); - return distOp.distance() <= distance; - } - - /** - * Compute the the nearest points of two geometries. - * The points are presented in the same order as the input Geometries. - * - * @param g0 a {@link Geometry} - * @param g1 another {@link Geometry} - * @return the nearest points in the geometries - */ - public static Coordinate[] nearestPoints(Geometry g0, Geometry g1) - { - DistanceOp distOp = new DistanceOp(g0, g1); - return distOp.nearestPoints(); - } - - /** - * Compute the the closest points of two geometries. - * The points are presented in the same order as the input Geometries. - * - * @param g0 a {@link Geometry} - * @param g1 another {@link Geometry} - * @return the closest points in the geometries - * @deprecated renamed to nearestPoints - */ - public static Coordinate[] closestPoints(Geometry g0, Geometry g1) - { - DistanceOp distOp = new DistanceOp(g0, g1); - return distOp.nearestPoints(); - } - - // input - private Geometry[] geom; - private double terminateDistance = 0.0; - // working - private PointLocator ptLocator = new PointLocator(); - private GeometryLocation[] minDistanceLocation; - private double minDistance = Double.MAX_VALUE; - - /** - * Constructs a DistanceOp that computes the distance and nearest points between - * the two specified geometries. - * @param g0 a Geometry - * @param g1 a Geometry - */ - public DistanceOp(Geometry g0, Geometry g1) - { - this(g0, g1, 0.0); - } - - /** - * Constructs a DistanceOp that computes the distance and nearest points between - * the two specified geometries. - * @param g0 a Geometry - * @param g1 a Geometry - * @param terminateDistance the distance on which to terminate the search - */ - public DistanceOp(Geometry g0, Geometry g1, double terminateDistance) - { - this.geom = new Geometry[2]; - geom[0] = g0; - geom[1] = g1; - this.terminateDistance = terminateDistance; - } - - /** - * Report the distance between the nearest points on the input geometries. - * - * @return the distance between the geometries - * or 0 if either input geometry is empty - * @throws IllegalArgumentException if either input geometry is null - */ - public double distance() - { - if (geom[0] == null || geom[1] == null) - throw new IllegalArgumentException("null geometries are not supported"); - if (geom[0].isEmpty() || geom[1].isEmpty()) - return 0.0; - - computeMinDistance(); - return minDistance; - } - - /** - * Report the coordinates of the nearest points in the input geometries. - * The points are presented in the same order as the input Geometries. - * - * @return a pair of {@link Coordinate}s of the nearest points - */ - public Coordinate[] nearestPoints() - { - computeMinDistance(); - Coordinate[] nearestPts - = new Coordinate[] { - minDistanceLocation[0].getCoordinate(), - minDistanceLocation[1].getCoordinate() }; - return nearestPts; - } - - /** - * - * @return a pair of {@link Coordinate}s of the nearest points - * @deprecated renamed to nearestPoints - */ - public Coordinate[] closestPoints() - { - return nearestPoints(); - } - - /** - * Report the locations of the nearest points in the input geometries. - * The locations are presented in the same order as the input Geometries. - * - * @return a pair of {@link GeometryLocation}s for the nearest points - */ - public GeometryLocation[] nearestLocations() - { - computeMinDistance(); - return minDistanceLocation; - } - - /** - * - * @return a pair of {@link GeometryLocation}s for the nearest points - * @deprecated renamed to nearestLocations - */ - public GeometryLocation[] closestLocations() - { - return nearestLocations(); - } - - private void updateMinDistance(GeometryLocation[] locGeom, boolean flip) - { - // if not set then don't update - if (locGeom[0] == null) return; - - if (flip) { - minDistanceLocation[0] = locGeom[1]; - minDistanceLocation[1] = locGeom[0]; - } - else { - minDistanceLocation[0] = locGeom[0]; - minDistanceLocation[1] = locGeom[1]; - } - } - - private void computeMinDistance() - { - // only compute once! - if (minDistanceLocation != null) return; - - minDistanceLocation = new GeometryLocation[2]; - computeContainmentDistance(); - if (minDistance <= terminateDistance) return; - computeFacetDistance(); - } - - private void computeContainmentDistance() - { - GeometryLocation[] locPtPoly = new GeometryLocation[2]; - // test if either geometry has a vertex inside the other - computeContainmentDistance(0, locPtPoly); - if (minDistance <= terminateDistance) return; - computeContainmentDistance(1, locPtPoly); - } - - private void computeContainmentDistance(int polyGeomIndex, GeometryLocation[] locPtPoly) - { - int locationsIndex = 1 - polyGeomIndex; - List polys = PolygonExtracter.getPolygons(geom[polyGeomIndex]); - if (polys.size() > 0) { - List insideLocs = ConnectedElementLocationFilter.getLocations(geom[locationsIndex]); - computeContainmentDistance(insideLocs, polys, locPtPoly); - if (minDistance <= terminateDistance) { - // this assigment is determined by the order of the args in the computeInside call above - minDistanceLocation[locationsIndex] = locPtPoly[0]; - minDistanceLocation[polyGeomIndex] = locPtPoly[1]; - return; - } - } - } - - private void computeContainmentDistance(List locs, List polys, GeometryLocation[] locPtPoly) - { - for (int i = 0; i < locs.size(); i++) { - GeometryLocation loc = (GeometryLocation) locs.get(i); - for (int j = 0; j < polys.size(); j++) { - computeContainmentDistance(loc, (Polygon) polys.get(j), locPtPoly); - if (minDistance <= terminateDistance) return; - } - } - } - - private void computeContainmentDistance(GeometryLocation ptLoc, - Polygon poly, - GeometryLocation[] locPtPoly) - { - Coordinate pt = ptLoc.getCoordinate(); - // if pt is not in exterior, distance to geom is 0 - if (Location.EXTERIOR != ptLocator.locate(pt, poly)) { - minDistance = 0.0; - locPtPoly[0] = ptLoc; - locPtPoly[1] = new GeometryLocation(poly, pt);; - return; - } - } - - /** - * Computes distance between facets (lines and points) - * of input geometries. - * - */ - private void computeFacetDistance() - { - GeometryLocation[] locGeom = new GeometryLocation[2]; - - /** - * Geometries are not wholely inside, so compute distance from lines and points - * of one to lines and points of the other - */ - List lines0 = LinearComponentExtracter.getLines(geom[0]); - List lines1 = LinearComponentExtracter.getLines(geom[1]); - - List pts0 = PointExtracter.getPoints(geom[0]); - List pts1 = PointExtracter.getPoints(geom[1]); - - // exit whenever minDistance goes LE than terminateDistance - computeMinDistanceLines(lines0, lines1, locGeom); - updateMinDistance(locGeom, false); - if (minDistance <= terminateDistance) return; - - locGeom[0] = null; - locGeom[1] = null; - computeMinDistanceLinesPoints(lines0, pts1, locGeom); - updateMinDistance(locGeom, false); - if (minDistance <= terminateDistance) return; - - locGeom[0] = null; - locGeom[1] = null; - computeMinDistanceLinesPoints(lines1, pts0, locGeom); - updateMinDistance(locGeom, true); - if (minDistance <= terminateDistance) return; - - locGeom[0] = null; - locGeom[1] = null; - computeMinDistancePoints(pts0, pts1, locGeom); - updateMinDistance(locGeom, false); - } - - private void computeMinDistanceLines(List lines0, List lines1, GeometryLocation[] locGeom) - { - for (int i = 0; i < lines0.size(); i++) { - LineString line0 = (LineString) lines0.get(i); - for (int j = 0; j < lines1.size(); j++) { - LineString line1 = (LineString) lines1.get(j); - computeMinDistance(line0, line1, locGeom); - if (minDistance <= terminateDistance) return; - } - } - } - - private void computeMinDistancePoints(List points0, List points1, GeometryLocation[] locGeom) - { - for (int i = 0; i < points0.size(); i++) { - Point pt0 = (Point) points0.get(i); - for (int j = 0; j < points1.size(); j++) { - Point pt1 = (Point) points1.get(j); - double dist = pt0.getCoordinate().distance(pt1.getCoordinate()); - if (dist < minDistance) { - minDistance = dist; - locGeom[0] = new GeometryLocation(pt0, 0, pt0.getCoordinate()); - locGeom[1] = new GeometryLocation(pt1, 0, pt1.getCoordinate()); - } - if (minDistance <= terminateDistance) return; - } - } - } - - private void computeMinDistanceLinesPoints(List lines, List points, - GeometryLocation[] locGeom) - { - for (int i = 0; i < lines.size(); i++) { - LineString line = (LineString) lines.get(i); - for (int j = 0; j < points.size(); j++) { - Point pt = (Point) points.get(j); - computeMinDistance(line, pt, locGeom); - if (minDistance <= terminateDistance) return; - } - } - } - - private void computeMinDistance(LineString line0, LineString line1, - GeometryLocation[] locGeom) - { - if (line0.getEnvelopeInternal().distance(line1.getEnvelopeInternal()) - > minDistance) - return; - Coordinate[] coord0 = line0.getCoordinates(); - Coordinate[] coord1 = line1.getCoordinates(); - // brute force approach! - for (int i = 0; i < coord0.length - 1; i++) { - for (int j = 0; j < coord1.length - 1; j++) { - double dist = CGAlgorithms.distanceLineLine( - coord0[i], coord0[i + 1], - coord1[j], coord1[j + 1] ); - if (dist < minDistance) { - minDistance = dist; - LineSegment seg0 = new LineSegment(coord0[i], coord0[i + 1]); - LineSegment seg1 = new LineSegment(coord1[j], coord1[j + 1]); - Coordinate[] closestPt = seg0.closestPoints(seg1); - locGeom[0] = new GeometryLocation(line0, i, closestPt[0]); - locGeom[1] = new GeometryLocation(line1, j, closestPt[1]); - } - if (minDistance <= terminateDistance) return; - } - } - } - - private void computeMinDistance(LineString line, Point pt, - GeometryLocation[] locGeom) - { - if (line.getEnvelopeInternal().distance(pt.getEnvelopeInternal()) - > minDistance) - return; - Coordinate[] coord0 = line.getCoordinates(); - Coordinate coord = pt.getCoordinate(); - // brute force approach! - for (int i = 0; i < coord0.length - 1; i++) { - double dist = CGAlgorithms.distancePointLine( - coord, coord0[i], coord0[i + 1] ); - if (dist < minDistance) { - minDistance = dist; - LineSegment seg = new LineSegment(coord0[i], coord0[i + 1]); - Coordinate segClosestPoint = seg.closestPoint(coord); - locGeom[0] = new GeometryLocation(line, i, segClosestPoint); - locGeom[1] = new GeometryLocation(pt, 0, coord); - } - if (minDistance <= terminateDistance) return; - - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequence.java b/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequence.java deleted file mode 100644 index 3395cfd0ec..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequence.java +++ /dev/null @@ -1,190 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.distance; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.*; - -/** - * Represents a sequence of facets (points or line segments) - * of a {@link Geometry} - * specified by a subsequence of a {@link CoordinateSequence}. - * - * @author Martin Davis - * - */ -public class FacetSequence -{ - private CoordinateSequence pts; - private int start; - private int end; - - // temporary Coordinates to materialize points from the CoordinateSequence - private Coordinate pt = new Coordinate(); - private Coordinate seqPt = new Coordinate(); - - /** - * Creates a new section based on a CoordinateSequence. - * - * @param pts the sequence holding the points in the section - * @param start the index of the start point - * @param end the index of the end point + 1 - */ - public FacetSequence(CoordinateSequence pts, int start, int end) - { - this.pts = pts; - this.start = start; - this.end = end; - } - - /** - * Creates a new sequence for a single point from a CoordinateSequence. - * - * @param pts the sequence holding the points in the facet sequence - * @param start the index of the point - */ - public FacetSequence(CoordinateSequence pts, int start) - { - this.pts = pts; - this.start = start; - this.end = start + 1; - } - - public Envelope getEnvelope() - { - Envelope env = new Envelope(); - for (int i = start; i < end; i++) { - env.expandToInclude(pts.getX(i), pts.getY(i)); - } - return env; - } - - public int size() - { - return end - start; - } - - public Coordinate getCoordinate(int index) - { - return pts.getCoordinate(start + index); - } - - public boolean isPoint() - { - return end - start == 1; - } - - - public double distance(FacetSequence facetSeq) - { - boolean isPoint = isPoint(); - boolean isPointOther = facetSeq.isPoint(); - - if (isPoint && isPointOther) { - pts.getCoordinate(start, pt); - facetSeq.pts.getCoordinate(facetSeq.start, seqPt); - return pt.distance(seqPt); - } - else if (isPoint) { - pts.getCoordinate(start, pt); - return computePointLineDistance(pt, facetSeq); - } - else if (isPointOther) { - facetSeq.pts.getCoordinate(facetSeq.start, seqPt); - return computePointLineDistance(seqPt, this); - } - return computeLineLineDistance(facetSeq); - - } - - // temporary Coordinates to materialize points from the CoordinateSequence - private Coordinate p0 = new Coordinate(); - private Coordinate p1 = new Coordinate(); - private Coordinate q0 = new Coordinate(); - private Coordinate q1 = new Coordinate(); - - private double computeLineLineDistance(FacetSequence facetSeq) - { - // both linear - compute minimum segment-segment distance - double minDistance = Double.MAX_VALUE; - - for (int i = start; i < end - 1; i++) { - for (int j = facetSeq.start; j < facetSeq.end - 1; j++) { - pts.getCoordinate(i, p0); - pts.getCoordinate(i + 1, p1); - facetSeq.pts.getCoordinate(j, q0); - facetSeq.pts.getCoordinate(j + 1, q1); - - double dist = CGAlgorithms.distanceLineLine(p0, p1, q0, q1); - if (dist == 0.0) - return 0.0; - if (dist < minDistance) { - minDistance = dist; - } - } - } - return minDistance; - } - - private double computePointLineDistance(Coordinate pt, FacetSequence facetSeq) - { - double minDistance = Double.MAX_VALUE; - - for (int i = facetSeq.start; i < facetSeq.end - 1; i++) { - facetSeq.pts.getCoordinate(i, q0); - facetSeq.pts.getCoordinate(i + 1, q1); - double dist = CGAlgorithms.distancePointLine(pt, q0, q1); - if (dist == 0.0) return 0.0; - if (dist < minDistance) { - minDistance = dist; - } - } - return minDistance; - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("LINESTRING ( "); - Coordinate p = new Coordinate(); - for (int i = start; i < end; i++) { - if (i > start) - buf.append(", "); - pts.getCoordinate(i, p); - buf.append(p.x + " " + p.y); - } - buf.append(" )"); - return buf.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java b/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java deleted file mode 100644 index 448d1a5ee2..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java +++ /dev/null @@ -1,106 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.distance; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryComponentFilter; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.geom.util.LinearComponentExtracter; -import com.vividsolutions.jts.index.strtree.STRtree; - -public class FacetSequenceTreeBuilder { - // 6 seems to be a good facet sequence size - private static final int FACET_SEQUENCE_SIZE = 6; - - // Seems to be better to use a minimum node capacity - private static final int STR_TREE_NODE_CAPACITY = 4; - - public static STRtree build(Geometry g) { - STRtree tree = new STRtree(STR_TREE_NODE_CAPACITY); - List sections = computeFacetSequences(g); - for (Iterator i = sections.iterator(); i.hasNext();) { - FacetSequence section = (FacetSequence) i.next(); - tree.insert(section.getEnvelope(), section); - } - tree.build(); - return tree; - } - - /** - * Creates facet sequences - * - * @param g - * @return List - */ - private static List computeFacetSequences(Geometry g) { - final List sections = new ArrayList(); - - g.apply(new GeometryComponentFilter() { - - public void filter(Geometry geom) { - CoordinateSequence seq = null; - if (geom instanceof LineString) { - seq = ((LineString) geom).getCoordinateSequence(); - addFacetSequences(seq, sections); - } - else if (geom instanceof Point) { - seq = ((Point) geom).getCoordinateSequence(); - addFacetSequences(seq, sections); - } - } - }); - return sections; - } - - private static void addFacetSequences(CoordinateSequence pts, List sections) { - int i = 0; - int size = pts.size(); - while (i <= size - 1) { - int end = i + FACET_SEQUENCE_SIZE + 1; - // if only one point remains after this section, include it in this - // section - if (end >= size - 1) - end = size; - FacetSequence sect = new FacetSequence(pts, i, end); - sections.add(sect); - i = i + FACET_SEQUENCE_SIZE; - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/GeometryLocation.java b/src/main/java/com/vividsolutions/jts/operation/distance/GeometryLocation.java deleted file mode 100644 index ae92f61490..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/GeometryLocation.java +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.distance; - -import com.vividsolutions.jts.geom.*; - -/** - * Represents the location of a point on a Geometry. - * Maintains both the actual point location - * (which may not be exact, if the point is not a vertex) - * as well as information about the component - * and segment index where the point occurs. - * Locations inside area Geometrys will not have an associated segment index, - * so in this case the segment index will have the sentinel value of - * {@link #INSIDE_AREA}. - * - * @version 1.7 - */ -public class GeometryLocation -{ - /** - * A special value of segmentIndex used for locations inside area geometries. - * These locations are not located on a segment, - * and thus do not have an associated segment index. - */ - public static final int INSIDE_AREA = -1; - - private Geometry component = null; - private int segIndex; - private Coordinate pt = null; - - /** - * Constructs a GeometryLocation specifying a point on a geometry, as well as the - * segment that the point is on - * (or {@link #INSIDE_AREA} if the point is not on a segment). - * - * @param component the component of the geometry containing the point - * @param segIndex the segment index of the location, or INSIDE_AREA - * @param pt the coordinate of the location - */ - public GeometryLocation(Geometry component, int segIndex, Coordinate pt) - { - this.component = component; - this.segIndex = segIndex; - this.pt = pt; - } - - /** - * Constructs a GeometryLocation specifying a point inside an area geometry. - * - * @param component the component of the geometry containing the point - * @param pt the coordinate of the location - */ - public GeometryLocation(Geometry component,Coordinate pt) - { - this(component, INSIDE_AREA, pt); - } - - /** - * Returns the geometry component on (or in) which this location occurs. - */ - public Geometry getGeometryComponent() { return component; } - - /** - * Returns the segment index for this location. If the location is inside an - * area, the index will have the value {@link #INSIDE_AREA}; - * - * @return the segment index for the location, or INSIDE_AREA - */ - public int getSegmentIndex() { return segIndex; } - - /** - * Returns the {@link Coordinate} of this location. - */ - public Coordinate getCoordinate() { return pt; } - - /** - * Tests whether this location represents a point inside an area geometry. - */ - public boolean isInsideArea() { return segIndex == INSIDE_AREA; } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java b/src/main/java/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java deleted file mode 100644 index b9f4b99229..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java +++ /dev/null @@ -1,188 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.distance; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.Lineal; -import com.vividsolutions.jts.geom.Polygonal; -import com.vividsolutions.jts.geom.Puntal; -import com.vividsolutions.jts.index.strtree.ItemBoundable; -import com.vividsolutions.jts.index.strtree.ItemDistance; -import com.vividsolutions.jts.index.strtree.STRtree; - -/** - * Computes the distance between the facets (segments and vertices) - * of two {@link Geometry}s - * using a Branch-and-Bound algorithm. - * The Branch-and-Bound algorithm operates over a - * traversal of R-trees built - * on the target and possibly also the query geometries. - *

                    - * This approach provides the following benefits: - *

                      - *
                    • Performance is improved due to the effects of the - * R-tree index - * and the pruning due to the Branch-and-Bound approach - *
                    • The spatial index on the target geometry can be cached - * to allow reuse in an incremental query situation. - *
                    - * Using this technique can be much more performant - * than using {@link #getDistance(Geometry)} - * when one or both - * input geometries are large, - * or when evaluating many distance computations against - * a single geometry. - *

                    - * This class is not thread-safe. - * - * @author Martin Davis - * - */ -public class IndexedFacetDistance -{ - /** - * Computes the distance between two geometries using - * the indexed approach. - *

                    - * For geometries with many segments or points, - * this can be faster than using a simple distance - * algorithm. - * - * @param g1 a geometry - * @param g2 a geometry - * @return the distance between the two geometries - */ - public static double distance(Geometry g1, Geometry g2) - { - IndexedFacetDistance dist = new IndexedFacetDistance(g1); - return dist.getDistance(g2); - } - - private STRtree cachedTree; - - /** - * Creates a new distance-finding instance for a given target {@link Geometry}. - *

                    - * Distances will be computed to all facets of the input geometry. - * The facets of the geometry are the discrete segments and points - * contained in its components. - * In the case of {@link Lineal} and {@link Puntal} inputs, - * this is equivalent to computing the conventional distance. - * In the case of {@link Polygonal} inputs, this is equivalent - * to computing the distance to the polygons boundaries. - * - * @param g1 a Geometry, which may be of any type. - */ - public IndexedFacetDistance(Geometry g1) { - cachedTree = FacetSequenceTreeBuilder.build(g1); - } - - /** - * Computes the distance from the base geometry to - * the given geometry. - * - * @param g the geometry to compute the distance to - * - * @return the computed distance - */ - public double getDistance(Geometry g) - { - STRtree tree2 = FacetSequenceTreeBuilder.build(g); - Object[] obj = cachedTree.nearestNeighbour(tree2, - new FacetSequenceDistance()); - return facetDistance(obj); - } - - private static double facetDistance(Object[] obj) - { - Object o1 = obj[0]; - Object o2 = obj[1]; - return ((FacetSequence) o1).distance((FacetSequence) o2); - } - - /** - * Computes the distance from the base geometry to - * the given geometry, up to and including a given - * maximum distance. - * - * @param g the geometry to compute the distance to - * @param maximumDistance the maximum distance to compute. - * - * @return the computed distance, - * or maximumDistance if the true distance is determined to be greater - */ - // TODO: implement this - /* - public double getDistanceWithin(Geometry g, double maximumDistance) - { - STRtree tree2 = FacetSequenceTreeBuilder.build(g); - Object[] obj = cachedTree.nearestNeighbours(tree2, - new FacetSequenceDistance()); - return facetDistance(obj); - } - */ - - - /** - * Tests whether the base geometry lies within - * a specified distance of the given geometry. - * -// * @param g the geometry to test -// * @param maximumDistance the maximum distance to test -// * @return true if the geometry lies with the specified distance - */ - // TODO: implement this - /* - public boolean isWithinDistance(Geometry g, double maximumDistance) - { - STRtree tree2 = FacetSequenceTreeBuilder.build(g); - double dist = findMinDistance(cachedTree.getRoot(), tree2.getRoot(), maximumDistance); - if (dist <= maximumDistance) - return false; - return true; - } - */ - - private static class FacetSequenceDistance - implements ItemDistance - { - public double distance(ItemBoundable item1, ItemBoundable item2) { - FacetSequence fs1 = (FacetSequence) item1.getItem(); - FacetSequence fs2 = (FacetSequence) item2.getItem(); - return fs1.distance(fs2); - } - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/operation/distance3d/AxisPlaneCoordinateSequence.java b/src/main/java/com/vividsolutions/jts/operation/distance3d/AxisPlaneCoordinateSequence.java deleted file mode 100644 index 2043de2540..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance3d/AxisPlaneCoordinateSequence.java +++ /dev/null @@ -1,159 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.distance3d; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Envelope; - -/** - * A CoordinateSequence wrapper which - * projects 3D coordinates into one of the - * three Cartesian axis planes, - * using the standard orthonormal projection - * (i.e. simply selecting the appropriate ordinates into the XY ordinates). - * The projected data is represented as 2D coordinates. - * - * @author mdavis - * - */ -public class AxisPlaneCoordinateSequence implements CoordinateSequence { - - /** - * Creates a wrapper projecting to the XY plane. - * - * @param seq the sequence to be projected - * @return a sequence which projects coordinates - */ - public static CoordinateSequence projectToXY(CoordinateSequence seq) - { - /** - * This is just a no-op, but return a wrapper - * to allow better testing - */ - return new AxisPlaneCoordinateSequence(seq, XY_INDEX); - } - - /** - * Creates a wrapper projecting to the XZ plane. - * - * @param seq the sequence to be projected - * @return a sequence which projects coordinates - */ - public static CoordinateSequence projectToXZ(CoordinateSequence seq) - { - return new AxisPlaneCoordinateSequence(seq, XZ_INDEX); - } - - /** - * Creates a wrapper projecting to the YZ plane. - * - * @param seq the sequence to be projected - * @return a sequence which projects coordinates - */ - public static CoordinateSequence projectToYZ(CoordinateSequence seq) - { - return new AxisPlaneCoordinateSequence(seq, YZ_INDEX); - } - - private static final int[] XY_INDEX = new int[] { 0,1 }; - private static final int[] XZ_INDEX = new int[] { 0,2 }; - private static final int[] YZ_INDEX = new int[] { 1,2 }; - - private CoordinateSequence seq; - private int[] indexMap; - - private AxisPlaneCoordinateSequence(CoordinateSequence seq, int[] indexMap) { - this.seq = seq; - this.indexMap = indexMap; - } - - public int getDimension() { - return 2; - } - - public Coordinate getCoordinate(int i) { - return getCoordinateCopy(i); - } - - public Coordinate getCoordinateCopy(int i) { - return new Coordinate(getX(i), getY(i), getZ(i)); - } - - public void getCoordinate(int index, Coordinate coord) { - coord.x = getOrdinate(index, X); - coord.y = getOrdinate(index, Y); - coord.z = getOrdinate(index, Z); - } - - public double getX(int index) { - return getOrdinate(index, X); - } - - public double getY(int index) { - return getOrdinate(index, Y); - } - - public double getZ(int index) { - return getOrdinate(index, Z); - } - - public double getOrdinate(int index, int ordinateIndex) { - // Z ord is always 0 - if (ordinateIndex > 1) return 0; - return seq.getOrdinate(index, indexMap[ordinateIndex]); - } - - public int size() { - return seq.size(); - } - - public void setOrdinate(int index, int ordinateIndex, double value) { - throw new UnsupportedOperationException(); - } - - public Coordinate[] toCoordinateArray() { - throw new UnsupportedOperationException(); - } - - public Envelope expandEnvelope(Envelope env) { - throw new UnsupportedOperationException(); - } - - public Object clone() - { - throw new UnsupportedOperationException(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance3d/Distance3DOp.java b/src/main/java/com/vividsolutions/jts/operation/distance3d/Distance3DOp.java deleted file mode 100644 index 4fff2ed40f..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance3d/Distance3DOp.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.distance3d; - -import com.vividsolutions.jts.algorithm.CGAlgorithms3D; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryCollection; -import com.vividsolutions.jts.geom.LineSegment; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.operation.distance.GeometryLocation; - -/** - * Find two points on two 3D {@link Geometry}s which lie within a given distance, - * or else are the nearest points on the geometries (in which case this also - * provides the distance between the geometries). - *

                    - * 3D geometries have vertex Z ordinates defined. - * 3D {@link Polygon}s are assumed to lie in a single plane (which is enforced if not actually the case). - * 3D {@link LineString}s and {link Point}s may have any configuration. - *

                    - * The distance computation also finds a pair of points in the input geometries - * which have the minimum distance between them. If a point lies in the interior - * of a line segment, the coordinate computed is a close approximation to the - * exact point. - *

                    - * The algorithms used are straightforward O(n^2) comparisons. This worst-case - * performance could be improved on by using Voronoi techniques or spatial - * indexes. - * - * @version 1.7 - */ -public class Distance3DOp { - /** - * Compute the distance between the nearest points of two geometries. - * - * @param g0 - * a {@link Geometry} - * @param g1 - * another {@link Geometry} - * @return the distance between the geometries - */ - public static double distance(Geometry g0, Geometry g1) { - Distance3DOp distOp = new Distance3DOp(g0, g1); - return distOp.distance(); - } - - /** - * Test whether two geometries lie within a given distance of each other. - * - * @param g0 - * a {@link Geometry} - * @param g1 - * another {@link Geometry} - * @param distance - * the distance to test - * @return true if g0.distance(g1) <= distance - */ - public static boolean isWithinDistance(Geometry g0, Geometry g1, - double distance) { - Distance3DOp distOp = new Distance3DOp(g0, g1, distance); - return distOp.distance() <= distance; - } - - /** - * Compute the the nearest points of two geometries. The points are - * presented in the same order as the input Geometries. - * - * @param g0 - * a {@link Geometry} - * @param g1 - * another {@link Geometry} - * @return the nearest points in the geometries - */ - public static Coordinate[] nearestPoints(Geometry g0, Geometry g1) { - Distance3DOp distOp = new Distance3DOp(g0, g1); - return distOp.nearestPoints(); - } - - // input - private Geometry[] geom; - private double terminateDistance = 0.0; - // working - private GeometryLocation[] minDistanceLocation; - private double minDistance = Double.MAX_VALUE; - private boolean isDone = false; - - /** - * Constructs a DistanceOp that computes the distance and nearest points - * between the two specified geometries. - * - * @param g0 - * a Geometry - * @param g1 - * a Geometry - */ - public Distance3DOp(Geometry g0, Geometry g1) { - this(g0, g1, 0.0); - } - - /** - * Constructs a DistanceOp that computes the distance and nearest points - * between the two specified geometries. - * - * @param g0 - * a Geometry - * @param g1 - * a Geometry - * @param terminateDistance - * the distance on which to terminate the search - */ - public Distance3DOp(Geometry g0, Geometry g1, double terminateDistance) { - this.geom = new Geometry[2]; - geom[0] = g0; - geom[1] = g1; - this.terminateDistance = terminateDistance; - } - - /** - * Report the distance between the nearest points on the input geometries. - * - * @return the distance between the geometries, or 0 if either input geometry is empty - * @throws IllegalArgumentException - * if either input geometry is null - */ - public double distance() { - if (geom[0] == null || geom[1] == null) - throw new IllegalArgumentException( - "null geometries are not supported"); - if (geom[0].isEmpty() || geom[1].isEmpty()) - return 0.0; - - computeMinDistance(); - return minDistance; - } - - /** - * Report the coordinates of the nearest points in the input geometries. The - * points are presented in the same order as the input Geometries. - * - * @return a pair of {@link Coordinate}s of the nearest points - */ - public Coordinate[] nearestPoints() { - computeMinDistance(); - Coordinate[] nearestPts = new Coordinate[] { - minDistanceLocation[0].getCoordinate(), - minDistanceLocation[1].getCoordinate() }; - return nearestPts; - } - - /** - * Report the locations of the nearest points in the input geometries. The - * locations are presented in the same order as the input Geometries. - * - * @return a pair of {@link GeometryLocation}s for the nearest points - */ - public GeometryLocation[] nearestLocations() { - computeMinDistance(); - return minDistanceLocation; - } - - private void updateDistance(double dist, - GeometryLocation loc0, GeometryLocation loc1, - boolean flip) { - this.minDistance = dist; - int index = flip ? 1 : 0; - minDistanceLocation[index] = loc0; - minDistanceLocation[1-index] = loc1; - if (minDistance < terminateDistance) - isDone = true; - } - - private void computeMinDistance() { - // only compute once - if (minDistanceLocation != null) - return; - minDistanceLocation = new GeometryLocation[2]; - - int geomIndex = mostPolygonalIndex(); - boolean flip = geomIndex == 0; - computeMinDistanceMultiMulti(geom[geomIndex], geom[1-geomIndex], flip); - } - - /** - * Finds the index of the "most polygonal" input geometry. - * This optimizes the computation of the best-fit plane, - * since it is cached only for the left-hand geometry. - * - * @return the index of the most polygonal geometry - */ - private int mostPolygonalIndex() { - int dim0 = geom[0].getDimension(); - int dim1 = geom[1].getDimension(); - if (dim0 >= 2 && dim1 >= 2) { - if (geom[0].getNumPoints() > geom[1].getNumPoints()) - return 0; - return 1; - } - // no more than one is dim 2 - if (dim0 >= 2) return 0; - if (dim1 >= 2) return 1; - // both dim <= 1 - don't flip - return 0; - } - - private void computeMinDistanceMultiMulti(Geometry g0, Geometry g1, boolean flip) { - if (g0 instanceof GeometryCollection) { - int n = g0.getNumGeometries(); - for (int i = 0; i < n; i++) { - Geometry g = g0.getGeometryN(i); - computeMinDistanceMultiMulti(g, g1, flip); - if (isDone) return; - } - } - else { - // handle case of multigeom component being empty - if (g0.isEmpty()) - return; - - // compute planar polygon only once for efficiency - if (g0 instanceof Polygon) { - computeMinDistanceOneMulti(polyPlane(g0), g1, flip); - } - else - computeMinDistanceOneMulti(g0, g1, flip); - } - } - - private void computeMinDistanceOneMulti(Geometry g0, Geometry g1, boolean flip) { - if (g1 instanceof GeometryCollection) { - int n = g1.getNumGeometries(); - for (int i = 0; i < n; i++) { - Geometry g = g1.getGeometryN(i); - computeMinDistanceOneMulti(g0, g, flip); - if (isDone) return; - } - } - else { - computeMinDistance(g0, g1, flip); - } - } - - private void computeMinDistanceOneMulti(PlanarPolygon3D poly, Geometry geom, boolean flip) { - if (geom instanceof GeometryCollection) { - int n = geom.getNumGeometries(); - for (int i = 0; i < n; i++) { - Geometry g = geom.getGeometryN(i); - computeMinDistanceOneMulti(poly, g, flip); - if (isDone) return; - } - } - else { - if (geom instanceof Point) { - computeMinDistancePolygonPoint(poly, (Point) geom, flip); - return; - } - if (geom instanceof LineString) { - computeMinDistancePolygonLine(poly, (LineString) geom, flip); - return; - } - if (geom instanceof Polygon) { - computeMinDistancePolygonPolygon(poly, (Polygon) geom, flip); - return; - } - } - } - - /** - * Convenience method to create a Plane3DPolygon - * @param poly - * @return - */ - private static PlanarPolygon3D polyPlane(Geometry poly) - { - return new PlanarPolygon3D((Polygon) poly); - } - - private void computeMinDistance(Geometry g0, Geometry g1, boolean flip) { - if (g0 instanceof Point) { - if (g1 instanceof Point) { - computeMinDistancePointPoint((Point) g0, (Point) g1, flip); - return; - } - if (g1 instanceof LineString) { - computeMinDistanceLinePoint((LineString) g1, (Point) g0, ! flip); - return; - } - if (g1 instanceof Polygon) { - computeMinDistancePolygonPoint(polyPlane(g1), (Point) g0, ! flip); - return; - } - } - if (g0 instanceof LineString) { - if (g1 instanceof Point) { - computeMinDistanceLinePoint((LineString) g0, (Point) g1, flip); - return; - } - if (g1 instanceof LineString) { - computeMinDistanceLineLine((LineString) g0, (LineString) g1, flip); - return; - } - if (g1 instanceof Polygon) { - computeMinDistancePolygonLine(polyPlane(g1), (LineString) g0, ! flip); - return; - } - } - if (g0 instanceof Polygon) { - if (g1 instanceof Point) { - computeMinDistancePolygonPoint(polyPlane(g0), (Point) g1, flip); - return; - } - if (g1 instanceof LineString) { - computeMinDistancePolygonLine(polyPlane(g0), (LineString) g1, flip); - return; - } - if (g1 instanceof Polygon) { - computeMinDistancePolygonPolygon(polyPlane(g0), (Polygon) g1, flip); - return; - } - } - } - - /** - * Computes distance between two polygons. - * - * To compute the distance, compute the distance - * between the rings of one polygon and the other polygon, - * and vice-versa. - * If the polygons intersect, then at least one ring must - * intersect the other polygon. - * Note that it is NOT sufficient to test only the shell rings. - * A counter-example is a "figure-8" polygon A - * and a simple polygon B at right angles to A, with the ring of B - * passing through the holes of A. - * The polygons intersect, - * but A's shell does not intersect B, and B's shell does not intersect A. - * - * @param poly0 - * @param poly1 - * @param geomIndex - */ - private void computeMinDistancePolygonPolygon(PlanarPolygon3D poly0, Polygon poly1, - boolean flip) { - computeMinDistancePolygonRings(poly0, poly1, flip); - if (isDone) return; - PlanarPolygon3D polyPlane1 = new PlanarPolygon3D(poly1); - computeMinDistancePolygonRings(polyPlane1, poly0.getPolygon(), flip); - } - - /** - * Compute distance between a polygon and the rings of another. - * - * @param poly - * @param ringPoly - * @param geomIndex - */ - private void computeMinDistancePolygonRings(PlanarPolygon3D poly, Polygon ringPoly, - boolean flip) { - // compute shell ring - computeMinDistancePolygonLine(poly, ringPoly.getExteriorRing(), flip); - if (isDone) return; - // compute hole rings - int nHole = ringPoly.getNumInteriorRing(); - for (int i = 0; i < nHole; i++) { - computeMinDistancePolygonLine(poly, ringPoly.getInteriorRingN(i), flip); - if (isDone) return; - } - } - - private void computeMinDistancePolygonLine(PlanarPolygon3D poly,LineString line, - boolean flip) { - - // first test if line intersects polygon - Coordinate intPt = intersection(poly, line); - if (intPt != null) { - updateDistance(0, - new GeometryLocation(poly.getPolygon(), 0, intPt), - new GeometryLocation(line, 0, intPt), - flip - ); - return; - } - - // if no intersection, then compute line distance to polygon rings - computeMinDistanceLineLine(poly.getPolygon().getExteriorRing(), line, flip); - if (isDone) return; - int nHole = poly.getPolygon().getNumInteriorRing(); - for (int i = 0; i < nHole; i++) { - computeMinDistanceLineLine(poly.getPolygon().getInteriorRingN(i), line, flip); - if (isDone) return; - } - } - - private Coordinate intersection(PlanarPolygon3D poly,LineString line) { - CoordinateSequence seq = line.getCoordinateSequence(); - if (seq.size() == 0) - return null; - - // start point of line - Coordinate p0 = new Coordinate(); - seq.getCoordinate(0, p0); - double d0 = poly.getPlane().orientedDistance(p0); - - // for each segment in the line - Coordinate p1 = new Coordinate(); - for (int i = 0; i < seq.size() - 1; i++) { - seq.getCoordinate(i, p0); - seq.getCoordinate(i + 1, p1); - double d1 = poly.getPlane().orientedDistance(p1); - - /** - * If the oriented distances of the segment endpoints have the same sign, - * the segment does not cross the plane, and is skipped. - */ - if (d0 * d1 > 0) - continue; - - /** - * Compute segment-plane intersection point - * which is then used for a point-in-polygon test. - * The endpoint distances to the plane d0 and d1 - * give the proportional distance of the intersection point - * along the segment. - */ - Coordinate intPt = segmentPoint(p0, p1, d0, d1); - // Coordinate intPt = polyPlane.intersection(p0, p1, s0, s1); - if (poly.intersects(intPt)) { - return intPt; - } - - // shift to next segment - d0 = d1; - } - return null; - } - - private void computeMinDistancePolygonPoint(PlanarPolygon3D polyPlane, Point point, - boolean flip) { - Coordinate pt = point.getCoordinate(); - - LineString shell = polyPlane.getPolygon().getExteriorRing(); - if (polyPlane.intersects(pt, shell)) { - // point is either inside or in a hole - - int nHole = polyPlane.getPolygon().getNumInteriorRing(); - for (int i = 0; i < nHole; i++) { - LineString hole = polyPlane.getPolygon().getInteriorRingN(i); - if (polyPlane.intersects(pt, hole)) { - computeMinDistanceLinePoint(hole, point, flip); - return; - } - } - // point is in interior of polygon - // distance is distance to polygon plane - double dist = Math.abs(polyPlane.getPlane().orientedDistance(pt)); - updateDistance(dist, - new GeometryLocation(polyPlane.getPolygon(), 0, pt), - new GeometryLocation(point, 0, pt), - flip - ); - } - // point is outside polygon, so compute distance to shell linework - computeMinDistanceLinePoint(shell, point, flip); - } - - private void computeMinDistanceLineLine(LineString line0, LineString line1, - boolean flip) { - Coordinate[] coord0 = line0.getCoordinates(); - Coordinate[] coord1 = line1.getCoordinates(); - // brute force approach! - for (int i = 0; i < coord0.length - 1; i++) { - for (int j = 0; j < coord1.length - 1; j++) { - double dist = CGAlgorithms3D.distanceSegmentSegment(coord0[i], - coord0[i + 1], coord1[j], coord1[j + 1]); - if (dist < minDistance) { - minDistance = dist; - // TODO: compute closest pts in 3D - LineSegment seg0 = new LineSegment(coord0[i], coord0[i + 1]); - LineSegment seg1 = new LineSegment(coord1[j], coord1[j + 1]); - Coordinate[] closestPt = seg0.closestPoints(seg1); - updateDistance(dist, - new GeometryLocation(line0, i, closestPt[0]), - new GeometryLocation(line1, j, closestPt[1]), - flip - ); - } - if (isDone) return; - } - } - } - - private void computeMinDistanceLinePoint(LineString line,Point point, - boolean flip) { - Coordinate[] lineCoord = line.getCoordinates(); - Coordinate coord = point.getCoordinate(); - // brute force approach! - for (int i = 0; i < lineCoord.length - 1; i++) { - double dist = CGAlgorithms3D.distancePointSegment(coord, lineCoord[i], - lineCoord[i + 1]); - if (dist < minDistance) { - LineSegment seg = new LineSegment(lineCoord[i], lineCoord[i + 1]); - Coordinate segClosestPoint = seg.closestPoint(coord); - updateDistance(dist, - new GeometryLocation(line, i, segClosestPoint), - new GeometryLocation(point, 0, coord), - flip); - } - if (isDone) return; - } - } - - private void computeMinDistancePointPoint(Point point0, Point point1, boolean flip) { - double dist = CGAlgorithms3D.distance( - point0.getCoordinate(), - point1.getCoordinate()); - if (dist < minDistance) { - updateDistance(dist, - new GeometryLocation(point0, 0, point0.getCoordinate()), - new GeometryLocation(point1, 0, point1.getCoordinate()), - flip); - } - } - - /** - * Computes a point at a distance along a segment - * specified by two relatively proportional values. - * The fractional distance along the segment is d0/(d0+d1). - * - * @param p0 - * start point of the segment - * @param p1 - * end point of the segment - * @param d0 - * proportional distance from start point to computed point - * @param d1 - * proportional distance from computed point to end point - * @return the computed point - */ - private static Coordinate segmentPoint(Coordinate p0, Coordinate p1, double d0, - double d1) { - if (d0 <= 0) return new Coordinate(p0); - if (d1 <= 0) return new Coordinate(p1); - - double f = Math.abs(d0) / (Math.abs(d0) + Math.abs(d1)); - double intx = p0.x + f * (p1.x - p0.x); - double inty = p0.y + f * (p1.y - p0.y); - double intz = p0.z + f * (p1.z - p0.z); - return new Coordinate(intx, inty, intz); - } - - - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/distance3d/PlanarPolygon3D.java b/src/main/java/com/vividsolutions/jts/operation/distance3d/PlanarPolygon3D.java deleted file mode 100644 index 003356d4bb..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/distance3d/PlanarPolygon3D.java +++ /dev/null @@ -1,195 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.distance3d; - -import com.vividsolutions.jts.algorithm.RayCrossingCounter; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Location; -import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.math.Plane3D; -import com.vividsolutions.jts.math.Vector3D; - -/** - * Models a polygon lying in a plane in 3-dimensional Cartesian space. - * The polygon representation is supplied - * by a {@link Polygon}, - * containing coordinates with XYZ ordinates. - * 3D polygons are assumed to lie in a single plane. - * The plane best fitting the polygon coordinates is - * computed and is represented by a {@link Plane3D}. - * - * @author mdavis - * - */ -public class PlanarPolygon3D { - - private Plane3D plane; - private Polygon poly; - private int facingPlane = -1; - - public PlanarPolygon3D(Polygon poly) { - this.poly = poly; - plane = findBestFitPlane(poly); - facingPlane = plane.closestAxisPlane(); - } - - /** - * Finds a best-fit plane for the polygon, - * by sampling a few points from the exterior ring. - *

                    - * The algorithm used is Newell's algorithm: - * - a base point for the plane is determined from the average of all vertices - * - the normal vector is determined by - * computing the area of the projections on each of the axis planes - * - * @param poly the polygon to determine the plane for - * @return the best-fit plane - */ - private Plane3D findBestFitPlane(Polygon poly) - { - CoordinateSequence seq = poly.getExteriorRing().getCoordinateSequence(); - Coordinate basePt = averagePoint(seq); - Vector3D normal = averageNormal(seq); - return new Plane3D(normal, basePt); - } - - /** - * Computes an average normal vector from a list of polygon coordinates. - * Uses Newell's method, which is based - * on the fact that the vector with components - * equal to the areas of the projection of the polygon onto - * the Cartesian axis planes is normal. - * - * @param seq the sequence of coordinates for the polygon - * @return a normal vector - */ - private Vector3D averageNormal(CoordinateSequence seq) - { - int n = seq.size(); - Coordinate sum = new Coordinate(0,0,0); - Coordinate p1 = new Coordinate(0,0,0); - Coordinate p2 = new Coordinate(0,0,0); - for (int i = 0; i < n - 1; i++) { - seq.getCoordinate(i, p1); - seq.getCoordinate(i+1, p2); - sum.x += (p1.y - p2.y)*(p1.z + p2.z); - sum.y += (p1.z - p2.z)*(p1.x + p2.x); - sum.z += (p1.x - p2.x)*(p1.y + p2.y); - } - sum.x /= n; - sum.y /= n; - sum.z /= n; - Vector3D norm = Vector3D.create(sum).normalize(); - return norm; - } - - /** - * Computes a point which is the average of all coordinates - * in a sequence. - * If the sequence lies in a single plane, - * the computed point also lies in the plane. - * - * @param seq a coordinate sequence - * @return a Coordinate with averaged ordinates - */ - private Coordinate averagePoint(CoordinateSequence seq) { - Coordinate a = new Coordinate(0,0,0); - int n = seq.size(); - for (int i = 0; i < n; i++) { - a.x += seq.getOrdinate(i, CoordinateSequence.X); - a.y += seq.getOrdinate(i, CoordinateSequence.Y); - a.z += seq.getOrdinate(i, CoordinateSequence.Z); - } - a.x /= n; - a.y /= n; - a.z /= n; - return a; - } - - public Plane3D getPlane() { - return plane; - } - - public Polygon getPolygon() { - return poly; - } - - public boolean intersects(Coordinate intPt) { - if (Location.EXTERIOR == locate(intPt, poly.getExteriorRing())) - return false; - - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - if (Location.INTERIOR == locate(intPt, poly.getInteriorRingN(i))) - return false; - } - return true; - } - - private int locate(Coordinate pt, LineString ring) { - CoordinateSequence seq = ring.getCoordinateSequence(); - CoordinateSequence seqProj = project(seq, facingPlane); - Coordinate ptProj = project(pt, facingPlane); - return RayCrossingCounter.locatePointInRing(ptProj, seqProj); - } - - public boolean intersects(Coordinate pt, LineString ring) { - CoordinateSequence seq = ring.getCoordinateSequence(); - CoordinateSequence seqProj = project(seq, facingPlane); - Coordinate ptProj = project(pt, facingPlane); - return Location.EXTERIOR != RayCrossingCounter.locatePointInRing(ptProj, seqProj); - } - - private static CoordinateSequence project(CoordinateSequence seq, int facingPlane) - { - switch (facingPlane) { - case Plane3D.XY_PLANE: return AxisPlaneCoordinateSequence.projectToXY(seq); - case Plane3D.XZ_PLANE: return AxisPlaneCoordinateSequence.projectToXZ(seq); - default: return AxisPlaneCoordinateSequence.projectToYZ(seq); - } - } - - private static Coordinate project(Coordinate p, int facingPlane) - { - switch (facingPlane) { - case Plane3D.XY_PLANE: return new Coordinate(p.x, p.y); - case Plane3D.XZ_PLANE: return new Coordinate(p.x, p.z); - // Plane3D.YZ - default: return new Coordinate(p.y, p.z); - } - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/EdgeString.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/EdgeString.java deleted file mode 100644 index 4b47322a40..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/EdgeString.java +++ /dev/null @@ -1,103 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateList; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * A sequence of {@link LineMergeDirectedEdge}s forming one of the lines that will - * be output by the line-merging process. - * - * @version 1.7 - */ -public class EdgeString { - private GeometryFactory factory; - private List directedEdges = new ArrayList(); - private Coordinate[] coordinates = null; - /** - * Constructs an EdgeString with the given factory used to convert this EdgeString - * to a LineString - */ - public EdgeString(GeometryFactory factory) { - this.factory = factory; - } - - /** - * Adds a directed edge which is known to form part of this line. - */ - public void add(LineMergeDirectedEdge directedEdge) { - directedEdges.add(directedEdge); - } - - private Coordinate[] getCoordinates() { - if (coordinates == null) { - int forwardDirectedEdges = 0; - int reverseDirectedEdges = 0; - CoordinateList coordinateList = new CoordinateList(); - for (Iterator i = directedEdges.iterator(); i.hasNext();) { - LineMergeDirectedEdge directedEdge = (LineMergeDirectedEdge) i.next(); - if (directedEdge.getEdgeDirection()) { - forwardDirectedEdges++; - } - else { - reverseDirectedEdges++; - } - coordinateList.add(((LineMergeEdge) directedEdge.getEdge()).getLine() - .getCoordinates(), false, - directedEdge.getEdgeDirection()); - } - coordinates = coordinateList.toCoordinateArray(); - if (reverseDirectedEdges > forwardDirectedEdges) { - CoordinateArrays.reverse(coordinates); - } - } - - return coordinates; - } - - /** - * Converts this EdgeString into a LineString. - */ - public LineString toLineString() { - return factory.createLineString(getCoordinates()); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java deleted file mode 100644 index 00a104e6ae..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java +++ /dev/null @@ -1,80 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.planargraph.DirectedEdge; -import com.vividsolutions.jts.planargraph.Node; -import com.vividsolutions.jts.util.Assert; - -/** - * A {@link com.vividsolutions.jts.planargraph.DirectedEdge} of a - * {@link LineMergeGraph}. - * - * @version 1.7 - */ -public class LineMergeDirectedEdge extends DirectedEdge { - /** - * Constructs a LineMergeDirectedEdge connecting the from node to the - * to node. - * - * @param directionPt - * specifies this DirectedEdge's direction (given by an imaginary - * line from the from node to directionPt) - * @param edgeDirection - * whether this DirectedEdge's direction is the same as or - * opposite to that of the parent Edge (if any) - */ - public LineMergeDirectedEdge(Node from, Node to, Coordinate directionPt, - boolean edgeDirection) { - super(from, to, directionPt, edgeDirection); - } - - /** - * Returns the directed edge that starts at this directed edge's end point, or null - * if there are zero or multiple directed edges starting there. - * @return the directed edge - */ - public LineMergeDirectedEdge getNext() { - if (getToNode().getDegree() != 2) { - return null; - } - if (getToNode().getOutEdges().getEdges().get(0) == getSym()) { - return (LineMergeDirectedEdge) getToNode().getOutEdges().getEdges().get(1); - } - Assert.isTrue(getToNode().getOutEdges().getEdges().get(1) == getSym()); - - return (LineMergeDirectedEdge) getToNode().getOutEdges().getEdges().get(0); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java deleted file mode 100644 index 619f353370..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java +++ /dev/null @@ -1,59 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.planargraph.Edge; - -/** - * An edge of a {@link LineMergeGraph}. The marked field indicates - * whether this Edge has been logically deleted from the graph. - * - * @version 1.7 - */ -public class LineMergeEdge extends Edge { - private LineString line; - /** - * Constructs a LineMergeEdge with vertices given by the specified LineString. - */ - public LineMergeEdge(LineString line) { - this.line = line; - } - /** - * Returns the LineString specifying the vertices of this edge. - */ - public LineString getLine() { - return line; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java deleted file mode 100644 index cc34686502..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateArrays; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.planargraph.DirectedEdge; -import com.vividsolutions.jts.planargraph.Edge; -import com.vividsolutions.jts.planargraph.Node; -import com.vividsolutions.jts.planargraph.PlanarGraph; - -/** - * A planar graph of edges that is analyzed to sew the edges together. The - * marked flag on @{link com.vividsolutions.planargraph.Edge}s - * and @{link com.vividsolutions.planargraph.Node}s indicates whether they have been - * logically deleted from the graph. - * - * @version 1.7 - */ -public class LineMergeGraph extends PlanarGraph -{ - /** - * Adds an Edge, DirectedEdges, and Nodes for the given LineString representation - * of an edge. - * Empty lines or lines with all coordinates equal are not added. - * - * @param lineString the linestring to add to the graph - */ - public void addEdge(LineString lineString) { - if (lineString.isEmpty()) { return; } - - Coordinate[] coordinates = CoordinateArrays.removeRepeatedPoints(lineString.getCoordinates()); - - // don't add lines with all coordinates equal - if (coordinates.length <= 1) return; - - Coordinate startCoordinate = coordinates[0]; - Coordinate endCoordinate = coordinates[coordinates.length - 1]; - Node startNode = getNode(startCoordinate); - Node endNode = getNode(endCoordinate); - DirectedEdge directedEdge0 = new LineMergeDirectedEdge(startNode, endNode, - coordinates[1], true); - DirectedEdge directedEdge1 = new LineMergeDirectedEdge(endNode, startNode, - coordinates[coordinates.length - 2], false); - Edge edge = new LineMergeEdge(lineString); - edge.setDirectedEdges(directedEdge0, directedEdge1); - add(edge); - } - - private Node getNode(Coordinate coordinate) { - Node node = findNode(coordinate); - if (node == null) { - node = new Node(coordinate); - add(node); - } - - return node; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMerger.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMerger.java deleted file mode 100644 index 5d8dfa2caa..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineMerger.java +++ /dev/null @@ -1,198 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryComponentFilter; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.planargraph.GraphComponent; -import com.vividsolutions.jts.planargraph.Node; -import com.vividsolutions.jts.util.Assert; - -/** - * Merges a collection of linear components to form maximal-length linestrings. - *

                    - * Merging stops at nodes of degree 1 or degree 3 or more. - * In other words, all nodes of degree 2 are merged together. - * The exception is in the case of an isolated loop, which only has degree-2 nodes. - * In this case one of the nodes is chosen as a starting point. - *

                    - * The direction of each - * merged LineString will be that of the majority of the LineStrings from which it - * was derived. - *

                    - * Any dimension of Geometry is handled - the constituent linework is extracted to - * form the edges. The edges must be correctly noded; that is, they must only meet - * at their endpoints. The LineMerger will accept non-noded input - * but will not merge non-noded edges. - *

                    - * Input lines which are empty or contain only a single unique coordinate are not included - * in the merging. - * - * @version 1.7 - */ -public class LineMerger -{ - private LineMergeGraph graph = new LineMergeGraph(); - private Collection mergedLineStrings = null; - private GeometryFactory factory = null; - - /** - * Creates a new line merger. - * - */ - public LineMerger() - { - - } - - /** - * Adds a Geometry to be processed. May be called multiple times. - * Any dimension of Geometry may be added; the constituent linework will be - * extracted. - * - * @param geometry geometry to be line-merged - */ - public void add(Geometry geometry) { - geometry.apply(new GeometryComponentFilter() { - public void filter(Geometry component) { - if (component instanceof LineString) { - add((LineString)component); - } - } - }); - } - /** - * Adds a collection of Geometries to be processed. May be called multiple times. - * Any dimension of Geometry may be added; the constituent linework will be - * extracted. - * - * @param geometries the geometries to be line-merged - */ - public void add(Collection geometries) - { - mergedLineStrings = null; - for (Iterator i = geometries.iterator(); i.hasNext(); ) { - Geometry geometry = (Geometry) i.next(); - add(geometry); - } - } - private void add(LineString lineString) { - if (factory == null) { - this.factory = lineString.getFactory(); - } - graph.addEdge(lineString); - } - - private Collection edgeStrings = null; - - private void merge() - { - if (mergedLineStrings != null) { return; } - - // reset marks (this allows incremental processing) - GraphComponent.setMarked(graph.nodeIterator(), false); - GraphComponent.setMarked(graph.edgeIterator(), false); - - edgeStrings = new ArrayList(); - buildEdgeStringsForObviousStartNodes(); - buildEdgeStringsForIsolatedLoops(); - mergedLineStrings = new ArrayList(); - for (Iterator i = edgeStrings.iterator(); i.hasNext(); ) { - EdgeString edgeString = (EdgeString) i.next(); - mergedLineStrings.add(edgeString.toLineString()); - } - } - - private void buildEdgeStringsForObviousStartNodes() { - buildEdgeStringsForNonDegree2Nodes(); - } - - private void buildEdgeStringsForIsolatedLoops() { - buildEdgeStringsForUnprocessedNodes(); - } - - private void buildEdgeStringsForUnprocessedNodes() { - for (Iterator i = graph.getNodes().iterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (!node.isMarked()) { - Assert.isTrue(node.getDegree() == 2); - buildEdgeStringsStartingAt(node); - node.setMarked(true); - } - } - } - private void buildEdgeStringsForNonDegree2Nodes() { - for (Iterator i = graph.getNodes().iterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (node.getDegree() != 2) { - buildEdgeStringsStartingAt(node); - node.setMarked(true); - } - } - } - private void buildEdgeStringsStartingAt(Node node) { - for (Iterator i = node.getOutEdges().iterator(); i.hasNext(); ) { - LineMergeDirectedEdge directedEdge = (LineMergeDirectedEdge) i.next(); - if (directedEdge.getEdge().isMarked()) { continue; } - edgeStrings.add(buildEdgeStringStartingWith(directedEdge)); - } - } - - private EdgeString buildEdgeStringStartingWith(LineMergeDirectedEdge start) { - EdgeString edgeString = new EdgeString(factory); - LineMergeDirectedEdge current = start; - do { - edgeString.add(current); - current.getEdge().setMarked(true); - current = current.getNext(); - } while (current != null && current != start); - return edgeString; - } - - /** - * Gets the {@link LineString}s created by the merging process. - * - * @return the collection of merged LineStrings - */ - public Collection getMergedLineStrings() { - merge(); - return mergedLineStrings; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineSequencer.java b/src/main/java/com/vividsolutions/jts/operation/linemerge/LineSequencer.java deleted file mode 100644 index 9cf35e98a0..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/linemerge/LineSequencer.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.linemerge; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.planargraph.*; -import com.vividsolutions.jts.planargraph.algorithm.ConnectedSubgraphFinder; -import com.vividsolutions.jts.util.Assert; - -/** - * Builds a sequence from a set of LineStrings so that - * they are ordered end to end. - * A sequence is a complete non-repeating list of the linear - * components of the input. Each linestring is oriented - * so that identical endpoints are adjacent in the list. - *

                    - * A typical use case is to convert a set of - * unoriented geometric links - * from a linear network - * (e.g. such as block faces on a bus route) - * into a continuous oriented path through the network. - *

                    - * The input linestrings may form one or more connected sets. - * The input linestrings should be correctly noded, or the results may - * not be what is expected. - * The computed output is a single {@link MultiLineString} containing the ordered - * linestrings in the sequence. - *

                    - * The sequencing employs the classic Eulerian path graph algorithm. - * Since Eulerian paths are not uniquely determined, - * further rules are used to - * make the computed sequence preserve as much as possible of the input - * ordering. - * Within a connected subset of lines, the ordering rules are: - *

                      - *
                    • If there is degree-1 node which is the start - * node of an linestring, use that node as the start of the sequence - *
                    • If there is a degree-1 node which is the end - * node of an linestring, use that node as the end of the sequence - *
                    • If the sequence has no degree-1 nodes, use any node as the start - *
                    - * - * Note that not all arrangements of lines can be sequenced. - * For a connected set of edges in a graph, - * Euler's Theorem states that there is a sequence containing each edge once - * if and only if there are no more than 2 nodes of odd degree. - * If it is not possible to find a sequence, the {@link #isSequenceable()} method - * will return false. - * - * @version 1.7 - */ -public class LineSequencer -{ - public static Geometry sequence(Geometry geom) - { - LineSequencer sequencer = new LineSequencer(); - sequencer.add(geom); - return sequencer.getSequencedLineStrings(); - } - - /** - * Tests whether a {@link Geometry} is sequenced correctly. - * {@link LineString}s are trivially sequenced. - * {@link MultiLineString}s are checked for correct sequencing. - * Otherwise, isSequenced is defined - * to be true for geometries that are not lineal. - * - * @param geom the geometry to test - * @return true if the geometry is sequenced or is not lineal - */ - public static boolean isSequenced(Geometry geom) - { - if (! (geom instanceof MultiLineString)) { - return true; - } - - MultiLineString mls = (MultiLineString) geom; - // the nodes in all subgraphs which have been completely scanned - Set prevSubgraphNodes = new TreeSet(); - - Coordinate lastNode = null; - List currNodes = new ArrayList(); - for (int i = 0; i < mls.getNumGeometries(); i++) { - LineString line = (LineString) mls.getGeometryN(i); - Coordinate startNode = line.getCoordinateN(0); - Coordinate endNode = line.getCoordinateN(line.getNumPoints() - 1); - - /** - * If this linestring is connected to a previous subgraph, geom is not sequenced - */ - if (prevSubgraphNodes.contains(startNode)) return false; - if (prevSubgraphNodes.contains(endNode)) return false; - - if (lastNode != null) { - if (! startNode.equals(lastNode)) { - // start new connected sequence - prevSubgraphNodes.addAll(currNodes); - currNodes.clear(); - } - } - currNodes.add(startNode); - currNodes.add(endNode); - lastNode = endNode; - } - return true; - } - - private LineMergeGraph graph = new LineMergeGraph(); - // initialize with default, in case no lines are input - private GeometryFactory factory = new GeometryFactory(); - private int lineCount = 0; - - private boolean isRun = false; - private Geometry sequencedGeometry = null; - private boolean isSequenceable = false; - - /** - * Adds a {@link Collection} of {@link Geometry}s to be sequenced. - * May be called multiple times. - * Any dimension of Geometry may be added; the constituent linework will be - * extracted. - * - * @param geometries a Collection of geometries to add - */ - public void add(Collection geometries) { - for (Iterator i = geometries.iterator(); i.hasNext(); ) { - Geometry geometry = (Geometry) i.next(); - add(geometry); - } - } - /** - * Adds a {@link Geometry} to be sequenced. - * May be called multiple times. - * Any dimension of Geometry may be added; the constituent linework will be - * extracted. - * - * @param geometry the geometry to add - */ - public void add(Geometry geometry) { - geometry.apply(new GeometryComponentFilter() { - public void filter(Geometry component) { - if (component instanceof LineString) { - addLine((LineString)component); - } - } - }); - } - - private void addLine(LineString lineString) { - if (factory == null) { - this.factory = lineString.getFactory(); - } - graph.addEdge(lineString); - lineCount++; - } - - /** - * Tests whether the arrangement of linestrings has a valid - * sequence. - * - * @return true if a valid sequence exists. - */ - public boolean isSequenceable() - { - computeSequence(); - return isSequenceable; - } - /** - * Returns the {@link LineString} or {@link MultiLineString} - * built by the sequencing process, if one exists. - * - * @return the sequenced linestrings, - * or null if a valid sequence does not exist - */ - public Geometry getSequencedLineStrings() { - computeSequence(); - return sequencedGeometry; - } - - private void computeSequence() { - if (isRun) { return; } - isRun = true; - - List sequences = findSequences(); - if (sequences == null) - return; - - sequencedGeometry = buildSequencedGeometry(sequences); - isSequenceable = true; - - int finalLineCount = sequencedGeometry.getNumGeometries(); - Assert.isTrue(lineCount == finalLineCount, "Lines were missing from result"); - Assert.isTrue(sequencedGeometry instanceof LineString - || sequencedGeometry instanceof MultiLineString, - "Result is not lineal"); - } - - private List findSequences() - { - List sequences = new ArrayList(); - ConnectedSubgraphFinder csFinder = new ConnectedSubgraphFinder(graph); - List subgraphs = csFinder.getConnectedSubgraphs(); - for (Iterator i = subgraphs.iterator(); i.hasNext(); ) { - Subgraph subgraph = (Subgraph) i.next(); - if (hasSequence(subgraph)) { - List seq = findSequence(subgraph); - sequences.add(seq); - } - else { - // if any subgraph cannot be sequenced, abort - return null; - } - } - return sequences; - } - - /** - * Tests whether a complete unique path exists in a graph - * using Euler's Theorem. - * - * @param graph the subgraph containing the edges - * @return true if a sequence exists - */ - private boolean hasSequence(Subgraph graph) - { - int oddDegreeCount = 0; - for (Iterator i = graph.nodeIterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (node.getDegree() % 2 == 1) - oddDegreeCount++; - } - return oddDegreeCount <= 2; - } - - private List findSequence(Subgraph graph) - { - GraphComponent.setVisited(graph.edgeIterator(), false); - - Node startNode = findLowestDegreeNode(graph); - DirectedEdge startDE = (DirectedEdge) startNode.getOutEdges().iterator().next(); - DirectedEdge startDESym = startDE.getSym(); - - List seq = new LinkedList(); - ListIterator lit = seq.listIterator(); - addReverseSubpath(startDESym, lit, false); - while (lit.hasPrevious()) { - DirectedEdge prev = (DirectedEdge) lit.previous(); - DirectedEdge unvisitedOutDE = findUnvisitedBestOrientedDE(prev.getFromNode()); - if (unvisitedOutDE != null) - addReverseSubpath(unvisitedOutDE.getSym(), lit, true); - } - - /** - * At this point, we have a valid sequence of graph DirectedEdges, but it - * is not necessarily appropriately oriented relative to the underlying - * geometry. - */ - List orientedSeq = orient(seq); - return orientedSeq; - } - - /** - * Finds an {@link DirectedEdge} for an unvisited edge (if any), - * choosing the dirEdge which preserves orientation, if possible. - * - * @param node the node to examine - * @return the dirEdge found, or null if none were unvisited - */ - private static DirectedEdge findUnvisitedBestOrientedDE(Node node) - { - DirectedEdge wellOrientedDE = null; - DirectedEdge unvisitedDE = null; - for (Iterator i = node.getOutEdges().iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - if (! de.getEdge().isVisited()) { - unvisitedDE = de; - if (de.getEdgeDirection()) - wellOrientedDE = de; - } - } - if (wellOrientedDE != null) - return wellOrientedDE; - return unvisitedDE; - } - - private void addReverseSubpath(DirectedEdge de, ListIterator lit, boolean expectedClosed) - { - // trace an unvisited path *backwards* from this de - Node endNode = de.getToNode(); - - Node fromNode = null; - while (true) { - lit.add(de.getSym()); - de.getEdge().setVisited(true); - fromNode = de.getFromNode(); - DirectedEdge unvisitedOutDE = findUnvisitedBestOrientedDE(fromNode); - // this must terminate, since we are continually marking edges as visited - if (unvisitedOutDE == null) - break; - de = unvisitedOutDE.getSym(); - } - if (expectedClosed) { - // the path should end at the toNode of this de, otherwise we have an error - Assert.isTrue(fromNode == endNode, "path not contiguous"); - } - } - - private static Node findLowestDegreeNode(Subgraph graph) - { - int minDegree = Integer.MAX_VALUE; - Node minDegreeNode = null; - for (Iterator i = graph.nodeIterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (minDegreeNode == null || node.getDegree() < minDegree) { - minDegree = node.getDegree(); - minDegreeNode = node; - } - } - return minDegreeNode; - } - - /** - * Computes a version of the sequence which is optimally - * oriented relative to the underlying geometry. - *

                    - * Heuristics used are: - *

                      - *
                    • If the path has a degree-1 node which is the start - * node of an linestring, use that node as the start of the sequence - *
                    • If the path has a degree-1 node which is the end - * node of an linestring, use that node as the end of the sequence - *
                    • If the sequence has no degree-1 nodes, use any node as the start - * (NOTE: in this case could orient the sequence according to the majority of the - * linestring orientations) - *
                    - * - * @param seq a List of DirectedEdges - * @return a List of DirectedEdges oriented appropriately - */ - private List orient(List seq) - { - DirectedEdge startEdge = (DirectedEdge) seq.get(0); - DirectedEdge endEdge = (DirectedEdge) seq.get(seq.size() - 1); - Node startNode = startEdge.getFromNode(); - Node endNode = endEdge.getToNode(); - - boolean flipSeq = false; - boolean hasDegree1Node = startNode.getDegree() == 1 - || endNode.getDegree() == 1; - - if (hasDegree1Node) { - boolean hasObviousStartNode = false; - - // test end edge before start edge, to make result stable - // (ie. if both are good starts, pick the actual start - if (endEdge.getToNode().getDegree() == 1 && endEdge.getEdgeDirection() == false) { - hasObviousStartNode = true; - flipSeq = true; - } - if (startEdge.getFromNode().getDegree() == 1 && startEdge.getEdgeDirection() == true) { - hasObviousStartNode = true; - flipSeq = false; - } - - // since there is no obvious start node, use any node of degree 1 - if (! hasObviousStartNode) { - // check if the start node should actually be the end node - if (startEdge.getFromNode().getDegree() == 1) - flipSeq = true; - // if the end node is of degree 1, it is properly the end node - } - - } - - - // if there is no degree 1 node, just use the sequence as is - // (Could insert heuristic of taking direction of majority of lines as overall direction) - - if (flipSeq) - return reverse(seq); - return seq; - } - - /** - * Reverse the sequence. - * This requires reversing the order of the dirEdges, and flipping - * each dirEdge as well - * - * @param seq a List of DirectedEdges, in sequential order - * @return the reversed sequence - */ - private List reverse(List seq) - { - LinkedList newSeq = new LinkedList(); - for (Iterator i = seq.iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - newSeq.addFirst(de.getSym()); - } - return newSeq; - } - - /** - * Builds a geometry ({@link LineString} or {@link MultiLineString} ) - * representing the sequence. - * - * @param sequences a List of Lists of DirectedEdges with - * LineMergeEdges as their parent edges. - * @return the sequenced geometry, or null if no sequence exists - */ - private Geometry buildSequencedGeometry(List sequences) - { - List lines = new ArrayList(); - - for (Iterator i1 = sequences.iterator(); i1.hasNext(); ) { - List seq = (List) i1.next(); - for (Iterator i2 = seq.iterator(); i2.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i2.next(); - LineMergeEdge e = (LineMergeEdge) de.getEdge(); - LineString line = e.getLine(); - - LineString lineToAdd = line; - if (! de.getEdgeDirection() && ! line.isClosed()) - lineToAdd = reverse(line); - - lines.add(lineToAdd); - } - } - if (lines.size() == 0) - return factory.createMultiLineString(new LineString[0]); - return factory.buildGeometry(lines); - } - - private static LineString reverse(LineString line) - { - Coordinate[] pts = line.getCoordinates(); - Coordinate[] revPts = new Coordinate[pts.length]; - int len = pts.length; - for (int i = 0; i < len; i++) { - revPts[len - 1 - i] = new Coordinate(pts[i]); - } - return line.getFactory().createLineString(revPts); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/ConsistentPolygonRingChecker.java b/src/main/java/com/vividsolutions/jts/operation/overlay/ConsistentPolygonRingChecker.java deleted file mode 100644 index 182b1c7800..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/ConsistentPolygonRingChecker.java +++ /dev/null @@ -1,160 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geomgraph.index.SegmentIntersector; -import com.vividsolutions.jts.operation.GeometryGraphOperation; - -/** - * Tests whether the polygon rings in a {@link GeometryGraph} - * are consistent. - * Used for checking if Topology errors are present after noding. - * - * @author Martin Davis - * @version 1.7 - */ -public class ConsistentPolygonRingChecker -{ - private PlanarGraph graph; - - public ConsistentPolygonRingChecker(PlanarGraph graph) { - this.graph = graph; - } - - public void checkAll() - { - check(OverlayOp.INTERSECTION); - check(OverlayOp.DIFFERENCE); - check(OverlayOp.UNION); - check(OverlayOp.SYMDIFFERENCE); - } - - /** - * Tests whether the result geometry is consistent - * - * @throws TopologyException if inconsistent topology is found - */ - public void check(int opCode) - { - for (Iterator nodeit = graph.getNodeIterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - testLinkResultDirectedEdges((DirectedEdgeStar) node.getEdges(), opCode); - } - } - - private List getPotentialResultAreaEdges(DirectedEdgeStar deStar, int opCode) - { -//print(System.out); - List resultAreaEdgeList = new ArrayList(); - for (Iterator it = deStar.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (isPotentialResultAreaEdge(de, opCode) || isPotentialResultAreaEdge(de.getSym(), opCode) ) - resultAreaEdgeList.add(de); - } - return resultAreaEdgeList; - } - - private boolean isPotentialResultAreaEdge(DirectedEdge de, int opCode) - { - // mark all dirEdges with the appropriate label - Label label = de.getLabel(); - if (label.isArea() - && ! de.isInteriorAreaEdge() - && OverlayOp.isResultOfOp( - label.getLocation(0, Position.RIGHT), - label.getLocation(1, Position.RIGHT), - opCode) - ) { - return true; -//Debug.print("in result "); Debug.println(de); - } - return false; - } - - private final int SCANNING_FOR_INCOMING = 1; - private final int LINKING_TO_OUTGOING = 2; - - private void testLinkResultDirectedEdges(DirectedEdgeStar deStar, int opCode) - { - // make sure edges are copied to resultAreaEdges list - List ringEdges = getPotentialResultAreaEdges(deStar, opCode); - // find first area edge (if any) to start linking at - DirectedEdge firstOut = null; - DirectedEdge incoming = null; - int state = SCANNING_FOR_INCOMING; - // link edges in CCW order - for (int i = 0; i < ringEdges.size(); i++) { - DirectedEdge nextOut = (DirectedEdge) ringEdges.get(i); - DirectedEdge nextIn = nextOut.getSym(); - - // skip de's that we're not interested in - if (! nextOut.getLabel().isArea()) continue; - - // record first outgoing edge, in order to link the last incoming edge - if (firstOut == null - && isPotentialResultAreaEdge(nextOut, opCode)) - firstOut = nextOut; - // assert: sym.isInResult() == false, since pairs of dirEdges should have been removed already - - switch (state) { - case SCANNING_FOR_INCOMING: - if (! isPotentialResultAreaEdge(nextIn, opCode)) continue; - incoming = nextIn; - state = LINKING_TO_OUTGOING; - break; - case LINKING_TO_OUTGOING: - if (! isPotentialResultAreaEdge(nextOut, opCode)) continue; - //incoming.setNext(nextOut); - state = SCANNING_FOR_INCOMING; - break; - } - } -//Debug.print(this); - if (state == LINKING_TO_OUTGOING) { -//Debug.print(firstOut == null, this); - if (firstOut == null) - throw new TopologyException("no outgoing dirEdge found", deStar.getCoordinate()); - } - - } - - - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java b/src/main/java/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java deleted file mode 100644 index d95b1a165b..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java +++ /dev/null @@ -1,78 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.algorithm.LineIntersector; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geomgraph.index.*; -import com.vividsolutions.jts.util.*; - -/** - * Nodes a set of edges. - * Takes one or more sets of edges and constructs a - * new set of edges consisting of all the split edges created by - * noding the input edges together - * @version 1.7 - */ -public class EdgeSetNoder { - - private LineIntersector li; - private List inputEdges = new ArrayList(); - - public EdgeSetNoder(LineIntersector li) { - this.li = li; - } - - public void addEdges(List edges) - { - inputEdges.addAll(edges); - } - - public List getNodedEdges() - { - EdgeSetIntersector esi = new SimpleMCSweepLineIntersector(); - SegmentIntersector si = new SegmentIntersector(li, true, false); - esi.computeIntersections(inputEdges, si, true); -//Debug.println("has proper int = " + si.hasProperIntersection()); - - List splitEdges = new ArrayList(); - for (Iterator i = inputEdges.iterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - e.getEdgeIntersectionList().addSplitEdges(splitEdges); - } - return splitEdges; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/LineBuilder.java b/src/main/java/com/vividsolutions/jts/operation/overlay/LineBuilder.java deleted file mode 100644 index dcb6412702..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/LineBuilder.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.util.*; - -/** - * Forms JTS LineStrings out of a the graph of {@link DirectedEdge}s - * created by an {@link OverlayOp}. - * - * @version 1.7 - */ -public class LineBuilder { - private OverlayOp op; - private GeometryFactory geometryFactory; - private PointLocator ptLocator; - - private List lineEdgesList = new ArrayList(); - private List resultLineList = new ArrayList(); - - public LineBuilder(OverlayOp op, GeometryFactory geometryFactory, PointLocator ptLocator) { - this.op = op; - this.geometryFactory = geometryFactory; - this.ptLocator = ptLocator; - } - /** - * @return a list of the LineStrings in the result of the specified overlay operation - */ - public List build(int opCode) - { - findCoveredLineEdges(); - collectLines(opCode); - //labelIsolatedLines(lineEdgesList); - buildLines(opCode); - return resultLineList; - } - /** - * Find and mark L edges which are "covered" by the result area (if any). - * L edges at nodes which also have A edges can be checked by checking - * their depth at that node. - * L edges at nodes which do not have A edges can be checked by doing a - * point-in-polygon test with the previously computed result areas. - */ - private void findCoveredLineEdges() - { - // first set covered for all L edges at nodes which have A edges too - for (Iterator nodeit = op.getGraph().getNodes().iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); -//node.print(System.out); - ((DirectedEdgeStar) node.getEdges()).findCoveredLineEdges(); - } - - /** - * For all L edges which weren't handled by the above, - * use a point-in-poly test to determine whether they are covered - */ - for (Iterator it = op.getGraph().getEdgeEnds().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - Edge e = de.getEdge(); - if (de.isLineEdge() && ! e.isCoveredSet()) { - boolean isCovered = op.isCoveredByA(de.getCoordinate()); - e.setCovered(isCovered); - } - } - } - - private void collectLines(int opCode) - { - for (Iterator it = op.getGraph().getEdgeEnds().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - collectLineEdge(de, opCode, lineEdgesList); - collectBoundaryTouchEdge(de, opCode, lineEdgesList); - } - } - - /** - * Collect line edges which are in the result. - * Line edges are in the result if they are not part of - * an area boundary, if they are in the result of the overlay operation, - * and if they are not covered by a result area. - * - * @param de the directed edge to test - * @param opCode the overlap operation - * @param edges the list of included line edges - */ - private void collectLineEdge(DirectedEdge de, int opCode, List edges) - { - Label label = de.getLabel(); - Edge e = de.getEdge(); - // include L edges which are in the result - if (de.isLineEdge()) { - if (! de.isVisited() && OverlayOp.isResultOfOp(label, opCode) && ! e.isCovered()) { -//Debug.println("de: " + de.getLabel()); -//Debug.println("edge: " + e.getLabel()); - - edges.add(e); - de.setVisitedEdge(true); - } - } - } - - /** - * Collect edges from Area inputs which should be in the result but - * which have not been included in a result area. - * This happens ONLY: - *
                      - *
                    • during an intersection when the boundaries of two - * areas touch in a line segment - *
                    • OR as a result of a dimensional collapse. - *
                    - */ - private void collectBoundaryTouchEdge(DirectedEdge de, int opCode, List edges) - { - Label label = de.getLabel(); - if (de.isLineEdge()) return; // only interested in area edges - if (de.isVisited()) return; // already processed - if (de.isInteriorAreaEdge()) return; // added to handle dimensional collapses - if (de.getEdge().isInResult()) return; // if the edge linework is already included, don't include it again - - // sanity check for labelling of result edgerings - Assert.isTrue(! (de.isInResult() || de.getSym().isInResult()) || ! de.getEdge().isInResult()); - - // include the linework if it's in the result of the operation - if (OverlayOp.isResultOfOp(label, opCode) - && opCode == OverlayOp.INTERSECTION) - { - edges.add(de.getEdge()); - de.setVisitedEdge(true); - } - } - - private void buildLines(int opCode) - { - for (Iterator it = lineEdgesList.iterator(); it.hasNext(); ) { - Edge e = (Edge) it.next(); - Label label = e.getLabel(); - LineString line = geometryFactory.createLineString(e.getCoordinates()); - resultLineList.add(line); - e.setInResult(true); - } - } - - private void labelIsolatedLines(List edgesList) - { - for (Iterator it = edgesList.iterator(); it.hasNext(); ) { - Edge e = (Edge) it.next(); - Label label = e.getLabel(); -//n.print(System.out); - if (e.isIsolated()) { - if (label.isNull(0)) - labelIsolatedLine(e, 0); - else - labelIsolatedLine(e, 1); - } - } - } - /** - * Label an isolated node with its relationship to the target geometry. - */ - private void labelIsolatedLine(Edge e, int targetIndex) - { - int loc = ptLocator.locate(e.getCoordinate(), op.getArgGeometry(targetIndex)); - e.getLabel().setLocation(targetIndex, loc); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java b/src/main/java/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java deleted file mode 100644 index fa857c732d..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java +++ /dev/null @@ -1,105 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * A ring of {@link DirectedEdge}s which may contain nodes of degree > 2. - * A MaximalEdgeRing may represent two different spatial entities: - *
                      - *
                    • a single polygon possibly containing inversions (if the ring is oriented CW) - *
                    • a single hole possibly containing exversions (if the ring is oriented CCW) - *
                    - * If the MaximalEdgeRing represents a polygon, - * the interior of the polygon is strongly connected. - *

                    - * These are the form of rings used to define polygons under some spatial data models. - * However, under the OGC SFS model, {@link MinimalEdgeRing}s are required. - * A MaximalEdgeRing can be converted to a list of MinimalEdgeRings using the - * {@link #buildMinimalRings() } method. - * - * @version 1.7 - * @see com.vividsolutions.jts.operation.overlay.MinimalEdgeRing - */ -public class MaximalEdgeRing - extends EdgeRing -{ - - public MaximalEdgeRing(DirectedEdge start, GeometryFactory geometryFactory) { - super(start, geometryFactory); - } - - public DirectedEdge getNext(DirectedEdge de) - { - return de.getNext(); - } - public void setEdgeRing(DirectedEdge de, EdgeRing er) - { - de.setEdgeRing(er); - } - - /** - * For all nodes in this EdgeRing, - * link the DirectedEdges at the node to form minimalEdgeRings - */ - public void linkDirectedEdgesForMinimalEdgeRings() - { - DirectedEdge de = startDe; - do { - Node node = de.getNode(); - ((DirectedEdgeStar) node.getEdges()).linkMinimalDirectedEdges(this); - de = de.getNext(); - } while (de != startDe); - } - - public List buildMinimalRings() - { - List minEdgeRings = new ArrayList(); - DirectedEdge de = startDe; - do { - if (de.getMinEdgeRing() == null) { - EdgeRing minEr = new MinimalEdgeRing(de, geometryFactory); - minEdgeRings.add(minEr); - } - de = de.getNext(); - } while (de != startDe); - return minEdgeRings; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java b/src/main/java/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java deleted file mode 100644 index 5860758722..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java +++ /dev/null @@ -1,66 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * A ring of {@link Edge}s with the property that no node - * has degree greater than 2. These are the form of rings required - * to represent polygons under the OGC SFS spatial data model. - * - * @version 1.7 - * @see com.vividsolutions.jts.operation.overlay.MaximalEdgeRing - */ -public class MinimalEdgeRing - extends EdgeRing -{ - - public MinimalEdgeRing(DirectedEdge start, GeometryFactory geometryFactory) { - super(start, geometryFactory); - } - - public DirectedEdge getNext(DirectedEdge de) - { - return de.getNextMin(); - } - public void setEdgeRing(DirectedEdge de, EdgeRing er) - { - de.setMinEdgeRing(er); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java b/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java deleted file mode 100644 index 5abefa16d4..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java +++ /dev/null @@ -1,56 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -/** - * @version 1.7 - */ -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Creates nodes for use in the {@link PlanarGraph}s constructed during - * overlay operations. - * - * @version 1.7 - */ -public class OverlayNodeFactory - extends NodeFactory -{ - public Node createNode(Coordinate coord) - { - return new Node(coord, new DirectedEdgeStar()); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayOp.java b/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayOp.java deleted file mode 100644 index c271a2e366..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/OverlayOp.java +++ /dev/null @@ -1,695 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.operation.GeometryGraphOperation; -import com.vividsolutions.jts.noding.*; - -/** - * Computes the geometric overlay of two {@link Geometry}s. The overlay - * can be used to determine any boolean combination of the geometries. - * - * @version 1.7 - */ -public class OverlayOp - extends GeometryGraphOperation -{ -/** - * The spatial functions supported by this class. - * These operations implement various boolean combinations of the resultants of the overlay. - */ - - /** - * The code for the Intersection overlay operation. - */ - public static final int INTERSECTION = 1; - - /** - * The code for the Union overlay operation. - */ - public static final int UNION = 2; - - /** - * The code for the Difference overlay operation. - */ - public static final int DIFFERENCE = 3; - - /** - * The code for the Symmetric Difference overlay operation. - */ - public static final int SYMDIFFERENCE = 4; - - /** - * Computes an overlay operation for - * the given geometry arguments. - * - * @param geom0 the first geometry argument - * @param geom1 the second geometry argument - * @param opCode the code for the desired overlay operation - * @return the result of the overlay operation - * @throws TopologyException if a robustness problem is encountered - */ - public static Geometry overlayOp(Geometry geom0, Geometry geom1, int opCode) - { - OverlayOp gov = new OverlayOp(geom0, geom1); - Geometry geomOv = gov.getResultGeometry(opCode); - return geomOv; - } - - /** - * Tests whether a point with a given topological {@link Label} - * relative to two geometries is contained in - * the result of overlaying the geometries using - * a given overlay operation. - *

                    - * The method handles arguments of {@link Location#NONE} correctly - * - * @param label the topological label of the point - * @param opCode the code for the overlay operation to test - * @return true if the label locations correspond to the overlayOpCode - */ - public static boolean isResultOfOp(Label label, int opCode) - { - int loc0 = label.getLocation(0); - int loc1 = label.getLocation(1); - return isResultOfOp(loc0, loc1, opCode); - } - - /** - * Tests whether a point with given {@link Location}s - * relative to two geometries is contained in - * the result of overlaying the geometries using - * a given overlay operation. - *

                    - * The method handles arguments of {@link Location#NONE} correctly - * - * @param loc0 the code for the location in the first geometry - * @param loc1 the code for the location in the second geometry - * @param overlayOpCode the code for the overlay operation to test - * @return true if the locations correspond to the overlayOpCode - */ - public static boolean isResultOfOp(int loc0, int loc1, int overlayOpCode) - { - if (loc0 == Location.BOUNDARY) loc0 = Location.INTERIOR; - if (loc1 == Location.BOUNDARY) loc1 = Location.INTERIOR; - switch (overlayOpCode) { - case INTERSECTION: - return loc0 == Location.INTERIOR - && loc1 == Location.INTERIOR; - case UNION: - return loc0 == Location.INTERIOR - || loc1 == Location.INTERIOR; - case DIFFERENCE: - return loc0 == Location.INTERIOR - && loc1 != Location.INTERIOR; - case SYMDIFFERENCE: - return ( loc0 == Location.INTERIOR && loc1 != Location.INTERIOR) - || ( loc0 != Location.INTERIOR && loc1 == Location.INTERIOR); - } - return false; - } - - private final PointLocator ptLocator = new PointLocator(); - private GeometryFactory geomFact; - private Geometry resultGeom; - - private PlanarGraph graph; - private EdgeList edgeList = new EdgeList(); - - private List resultPolyList = new ArrayList(); - private List resultLineList = new ArrayList(); - private List resultPointList = new ArrayList(); - - /** - * Constructs an instance to compute a single overlay operation - * for the given geometries. - * - * @param g0 the first geometry argument - * @param g1 the second geometry argument - */ - public OverlayOp(Geometry g0, Geometry g1) { - super(g0, g1); - graph = new PlanarGraph(new OverlayNodeFactory()); - /** - * Use factory of primary geometry. - * Note that this does NOT handle mixed-precision arguments - * where the second arg has greater precision than the first. - */ - geomFact = g0.getFactory(); - } - - /** - * Gets the result of the overlay for a given overlay operation. - *

                    - * Note: this method can be called once only. - * - * @param overlayOpCode the overlay operation to perform - * @return the compute result geometry - * @throws TopologyException if a robustness problem is encountered - */ - public Geometry getResultGeometry(int overlayOpCode) - { - computeOverlay(overlayOpCode); - return resultGeom; - } - - /** - * Gets the graph constructed to compute the overlay. - * - * @return the overlay graph - */ - public PlanarGraph getGraph() { return graph; } - - private void computeOverlay(int opCode) - { - // copy points from input Geometries. - // This ensures that any Point geometries - // in the input are considered for inclusion in the result set - copyPoints(0); - copyPoints(1); - - // node the input Geometries - arg[0].computeSelfNodes(li, false); - arg[1].computeSelfNodes(li, false); - - // compute intersections between edges of the two input geometries - arg[0].computeEdgeIntersections(arg[1], li, true); - - List baseSplitEdges = new ArrayList(); - arg[0].computeSplitEdges(baseSplitEdges); - arg[1].computeSplitEdges(baseSplitEdges); - List splitEdges = baseSplitEdges; - // add the noded edges to this result graph - insertUniqueEdges(baseSplitEdges); - - computeLabelsFromDepths(); - replaceCollapsedEdges(); - -//Debug.println(edgeList); - - /** - * Check that the noding completed correctly. - * - * This test is slow, but necessary in order to catch robustness failure - * situations. - * If an exception is thrown because of a noding failure, - * then snapping will be performed, which will hopefully avoid the problem. - * In the future hopefully a faster check can be developed. - * - */ - EdgeNodingValidator.checkValid(edgeList.getEdges()); - - graph.addEdges(edgeList.getEdges()); - computeLabelling(); -//Debug.printWatch(); - labelIncompleteNodes(); -//Debug.printWatch(); -//nodeMap.print(System.out); - - /** - * The ordering of building the result Geometries is important. - * Areas must be built before lines, which must be built before points. - * This is so that lines which are covered by areas are not included - * explicitly, and similarly for points. - */ - findResultAreaEdges(opCode); - cancelDuplicateResultEdges(); - - PolygonBuilder polyBuilder = new PolygonBuilder(geomFact); - polyBuilder.add(graph); - resultPolyList = polyBuilder.getPolygons(); - - LineBuilder lineBuilder = new LineBuilder(this, geomFact, ptLocator); - resultLineList = lineBuilder.build(opCode); - - PointBuilder pointBuilder = new PointBuilder(this, geomFact, ptLocator); - resultPointList = pointBuilder.build(opCode); - - // gather the results from all calculations into a single Geometry for the result set - resultGeom = computeGeometry(resultPointList, resultLineList, resultPolyList, opCode); - } - - private void insertUniqueEdges(List edges) - { - for (Iterator i = edges.iterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - insertUniqueEdge(e); - } - } - /** - * Insert an edge from one of the noded input graphs. - * Checks edges that are inserted to see if an - * identical edge already exists. - * If so, the edge is not inserted, but its label is merged - * with the existing edge. - */ - protected void insertUniqueEdge(Edge e) - { -// MD 8 Oct 03 speed up identical edge lookup - // fast lookup - Edge existingEdge = edgeList.findEqualEdge(e); - - // If an identical edge already exists, simply update its label - if (existingEdge != null) { - Label existingLabel = existingEdge.getLabel(); - - Label labelToMerge = e.getLabel(); - // check if new edge is in reverse direction to existing edge - // if so, must flip the label before merging it - if (! existingEdge.isPointwiseEqual(e)) { - labelToMerge = new Label(e.getLabel()); - labelToMerge.flip(); - } - Depth depth = existingEdge.getDepth(); - // if this is the first duplicate found for this edge, initialize the depths - ///* - if (depth.isNull()) { - depth.add(existingLabel); - } - //*/ - depth.add(labelToMerge); - existingLabel.merge(labelToMerge); -//Debug.print("inserted edge: "); Debug.println(e); -//Debug.print("existing edge: "); Debug.println(existingEdge); - - } - else { // no matching existing edge was found - // add this new edge to the list of edges in this graph - //e.setName(name + edges.size()); - //e.getDepth().add(e.getLabel()); - edgeList.add(e); - } - } - - /** - * If either of the GeometryLocations for the existing label is - * exactly opposite to the one in the labelToMerge, - * this indicates a dimensional collapse has happened. - * In this case, convert the label for that Geometry to a Line label - */ - /* NOT NEEDED? - private void checkDimensionalCollapse(Label labelToMerge, Label existingLabel) - { - if (existingLabel.isArea() && labelToMerge.isArea()) { - for (int i = 0; i < 2; i++) { - if (! labelToMerge.isNull(i) - && labelToMerge.getLocation(i, Position.LEFT) == existingLabel.getLocation(i, Position.RIGHT) - && labelToMerge.getLocation(i, Position.RIGHT) == existingLabel.getLocation(i, Position.LEFT) ) - { - existingLabel.toLine(i); - } - } - } - } - */ - /** - * Update the labels for edges according to their depths. - * For each edge, the depths are first normalized. - * Then, if the depths for the edge are equal, - * this edge must have collapsed into a line edge. - * If the depths are not equal, update the label - * with the locations corresponding to the depths - * (i.e. a depth of 0 corresponds to a Location of EXTERIOR, - * a depth of 1 corresponds to INTERIOR) - */ - private void computeLabelsFromDepths() - { - for (Iterator it = edgeList.iterator(); it.hasNext(); ) { - Edge e = (Edge) it.next(); - Label lbl = e.getLabel(); - Depth depth = e.getDepth(); - /** - * Only check edges for which there were duplicates, - * since these are the only ones which might - * be the result of dimensional collapses. - */ - if (! depth.isNull()) { - depth.normalize(); - for (int i = 0; i < 2; i++) { - if (! lbl.isNull(i) && lbl.isArea() && ! depth.isNull(i)) { - /** - * if the depths are equal, this edge is the result of - * the dimensional collapse of two or more edges. - * It has the same location on both sides of the edge, - * so it has collapsed to a line. - */ - if (depth.getDelta(i) == 0) { - lbl.toLine(i); - } - else { - /** - * This edge may be the result of a dimensional collapse, - * but it still has different locations on both sides. The - * label of the edge must be updated to reflect the resultant - * side locations indicated by the depth values. - */ - Assert.isTrue(! depth.isNull(i, Position.LEFT), "depth of LEFT side has not been initialized"); - lbl.setLocation(i, Position.LEFT, depth.getLocation(i, Position.LEFT)); - Assert.isTrue(! depth.isNull(i, Position.RIGHT), "depth of RIGHT side has not been initialized"); - lbl.setLocation(i, Position.RIGHT, depth.getLocation(i, Position.RIGHT)); - } - } - } - } - } - } - /** - * If edges which have undergone dimensional collapse are found, - * replace them with a new edge which is a L edge - */ - private void replaceCollapsedEdges() - { - List newEdges = new ArrayList(); - for (Iterator it = edgeList.iterator(); it.hasNext(); ) { - Edge e = (Edge) it.next(); - if (e.isCollapsed()) { -//Debug.print(e); - it.remove(); - newEdges.add(e.getCollapsedEdge()); - } - } - edgeList.addAll(newEdges); - } - /** - * Copy all nodes from an arg geometry into this graph. - * The node label in the arg geometry overrides any previously computed - * label for that argIndex. - * (E.g. a node may be an intersection node with - * a previously computed label of BOUNDARY, - * but in the original arg Geometry it is actually - * in the interior due to the Boundary Determination Rule) - */ - private void copyPoints(int argIndex) - { - for (Iterator i = arg[argIndex].getNodeIterator(); i.hasNext(); ) { - Node graphNode = (Node) i.next(); - Node newNode = graph.addNode(graphNode.getCoordinate()); - newNode.setLabel(argIndex, graphNode.getLabel().getLocation(argIndex)); - } - } - - /** - * Compute initial labelling for all DirectedEdges at each node. - * In this step, DirectedEdges will acquire a complete labelling - * (i.e. one with labels for both Geometries) - * only if they - * are incident on a node which has edges for both Geometries - */ - private void computeLabelling() - { - for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); -//if (node.getCoordinate().equals(new Coordinate(222, 100)) ) Debug.addWatch(node.getEdges()); - node.getEdges().computeLabelling(arg); - } - mergeSymLabels(); - updateNodeLabelling(); - } - /** - * For nodes which have edges from only one Geometry incident on them, - * the previous step will have left their dirEdges with no labelling for the other - * Geometry. However, the sym dirEdge may have a labelling for the other - * Geometry, so merge the two labels. - */ - private void mergeSymLabels() - { - for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - ((DirectedEdgeStar) node.getEdges()).mergeSymLabels(); -//node.print(System.out); - } - } - private void updateNodeLabelling() - { - // update the labels for nodes - // The label for a node is updated from the edges incident on it - // (Note that a node may have already been labelled - // because it is a point in one of the input geometries) - for (Iterator nodeit = graph.getNodes().iterator(); nodeit.hasNext(); ) { - Node node = (Node) nodeit.next(); - Label lbl = ((DirectedEdgeStar) node.getEdges()).getLabel(); - node.getLabel().merge(lbl); - } - } - - /** - * Incomplete nodes are nodes whose labels are incomplete. - * (e.g. the location for one Geometry is null). - * These are either isolated nodes, - * or nodes which have edges from only a single Geometry incident on them. - * - * Isolated nodes are found because nodes in one graph which don't intersect - * nodes in the other are not completely labelled by the initial process - * of adding nodes to the nodeList. - * To complete the labelling we need to check for nodes that lie in the - * interior of edges, and in the interior of areas. - *

                    - * When each node labelling is completed, the labelling of the incident - * edges is updated, to complete their labelling as well. - */ - private void labelIncompleteNodes() - { - int nodeCount = 0; - for (Iterator ni = graph.getNodes().iterator(); ni.hasNext(); ) { - Node n = (Node) ni.next(); - Label label = n.getLabel(); - if (n.isIsolated()) { - nodeCount++; - if (label.isNull(0)) - labelIncompleteNode(n, 0); - else - labelIncompleteNode(n, 1); - } - // now update the labelling for the DirectedEdges incident on this node - ((DirectedEdgeStar) n.getEdges()).updateLabelling(label); -//n.print(System.out); - } - /* - int nPoly0 = arg[0].getGeometry().getNumGeometries(); - int nPoly1 = arg[1].getGeometry().getNumGeometries(); - System.out.println("# isolated nodes= " + nodeCount - + " # poly[0] = " + nPoly0 - + " # poly[1] = " + nPoly1); - */ - } - - /** - * Label an isolated node with its relationship to the target geometry. - */ - private void labelIncompleteNode(Node n, int targetIndex) - { - int loc = ptLocator.locate(n.getCoordinate(), arg[targetIndex].getGeometry()); - - // MD - 2008-10-24 - experimental for now -// int loc = arg[targetIndex].locate(n.getCoordinate()); - n.getLabel().setLocation(targetIndex, loc); - } - - /** - * Find all edges whose label indicates that they are in the result area(s), - * according to the operation being performed. Since we want polygon shells to be - * oriented CW, choose dirEdges with the interior of the result on the RHS. - * Mark them as being in the result. - * Interior Area edges are the result of dimensional collapses. - * They do not form part of the result area boundary. - */ - private void findResultAreaEdges(int opCode) - { - for (Iterator it = graph.getEdgeEnds().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - // mark all dirEdges with the appropriate label - Label label = de.getLabel(); - if (label.isArea() - && ! de.isInteriorAreaEdge() - && isResultOfOp( - label.getLocation(0, Position.RIGHT), - label.getLocation(1, Position.RIGHT), - opCode)) { - de.setInResult(true); -//Debug.print("in result "); Debug.println(de); - } - } - } - /** - * If both a dirEdge and its sym are marked as being in the result, cancel - * them out. - */ - private void cancelDuplicateResultEdges() - { - // remove any dirEdges whose sym is also included - // (they "cancel each other out") - for (Iterator it = graph.getEdgeEnds().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - DirectedEdge sym = de.getSym(); - if (de.isInResult() && sym.isInResult()) { - de.setInResult(false); - sym.setInResult(false); -//Debug.print("cancelled "); Debug.println(de); Debug.println(sym); - } - } - } - /** - * Tests if a point node should be included in the result or not. - * - * @param coord the point coordinate - * @return true if the coordinate point is covered by a result Line or Area geometry - */ - public boolean isCoveredByLA(Coordinate coord) - { - if (isCovered(coord, resultLineList)) return true; - if (isCovered(coord, resultPolyList)) return true; - return false; - } - /** - * Tests if an L edge should be included in the result or not. - * - * @param coord the point coordinate - * @return true if the coordinate point is covered by a result Area geometry - */ - public boolean isCoveredByA(Coordinate coord) - { - if (isCovered(coord, resultPolyList)) return true; - return false; - } - /** - * @return true if the coord is located in the interior or boundary of - * a geometry in the list. - */ - private boolean isCovered(Coordinate coord, List geomList) - { - for (Iterator it = geomList.iterator(); it.hasNext(); ) { - Geometry geom = (Geometry) it.next(); - int loc = ptLocator.locate(coord, geom); - if (loc != Location.EXTERIOR) return true; - } - return false; - } - - private Geometry computeGeometry( List resultPointList, - List resultLineList, - List resultPolyList, - int opcode) - { - List geomList = new ArrayList(); - // element geometries of the result are always in the order P,L,A - geomList.addAll(resultPointList); - geomList.addAll(resultLineList); - geomList.addAll(resultPolyList); - - //* - if (geomList.isEmpty()) - return createEmptyResult(opcode, arg[0].getGeometry(), arg[1].getGeometry(), geomFact); - //*/ - - // build the most specific geometry possible - return geomFact.buildGeometry(geomList); - } - - /** - * Creates an empty result geometry of the appropriate dimension, - * based on the given overlay operation and the dimensions of the inputs. - * The created geometry is always an atomic geometry, - * not a collection. - *

                    - * The empty result is constructed using the following rules: - *

                      - *
                    • {@link #INTERSECTION} - result has the dimension of the lowest input dimension - *
                    • {@link #UNION} - result has the dimension of the highest input dimension - *
                    • {@link #DIFFERENCE} - result has the dimension of the left-hand input - *
                    • {@link #SYMDIFFERENCE} - result has the dimension of the highest input dimension - * (since the symmetric Difference is the union of the differences). - *
                    • - * - * @param overlayOpCode the code for the overlay operation being performed - * @param a an input geometry - * @param b an input geometry - * @param geomFact the geometry factory being used for the operation - * @return an empty atomic geometry of the appropriate dimension - */ - public static Geometry createEmptyResult(int overlayOpCode, Geometry a, Geometry b, GeometryFactory geomFact) - { - Geometry result = null; - switch (resultDimension(overlayOpCode, a, b)) { - case -1: - result = geomFact.createGeometryCollection(new Geometry[0]); - break; - case 0: - result = geomFact.createPoint((Coordinate) null); - break; - case 1: - result = geomFact.createLineString((Coordinate[]) null); - break; - case 2: - result = geomFact.createPolygon(null, null); - break; - } - return result; - } - - private static int resultDimension(int opCode, Geometry g0, Geometry g1) - { - int dim0 = g0.getDimension(); - int dim1 = g1.getDimension(); - - int resultDimension = -1; - switch (opCode) { - case INTERSECTION: - resultDimension = Math.min(dim0, dim1); - break; - case UNION: - resultDimension = Math.max(dim0, dim1); - break; - case DIFFERENCE: - resultDimension = dim0; - break; - case SYMDIFFERENCE: - /** - * This result is chosen because - *
                      -  	   * SymDiff = Union(Diff(A, B), Diff(B, A)
                      -  	   * 
                      - * and Union has the dimension of the highest-dimension argument. - */ - resultDimension = Math.max(dim0, dim1); - break; - } - return resultDimension; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/PointBuilder.java b/src/main/java/com/vividsolutions/jts/operation/overlay/PointBuilder.java deleted file mode 100644 index 08201125df..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/PointBuilder.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Constructs {@link Point}s from the nodes of an overlay graph. - * @version 1.7 - */ -public class PointBuilder { - private OverlayOp op; - private GeometryFactory geometryFactory; - private List resultPointList = new ArrayList(); - - public PointBuilder(OverlayOp op, GeometryFactory geometryFactory, PointLocator ptLocator) { - this.op = op; - this.geometryFactory = geometryFactory; - // ptLocator is never used in this class - } - - /** - * Computes the Point geometries which will appear in the result, - * given the specified overlay operation. - * - * @return a list of the Points objects in the result - */ - public List build(int opCode) - { - extractNonCoveredResultNodes(opCode); - /** - * It can happen that connected result nodes are still covered by - * result geometries, so must perform this filter. - * (For instance, this can happen during topology collapse). - */ - return resultPointList; - } - - /** - * Determines nodes which are in the result, and creates {@link Point}s for them. - * - * This method determines nodes which are candidates for the result via their - * labelling and their graph topology. - * - * @param opCode the overlay operation - */ - private void extractNonCoveredResultNodes(int opCode) - { - // testing only - //if (true) return resultNodeList; - - for (Iterator nodeit = op.getGraph().getNodes().iterator(); nodeit.hasNext(); ) { - Node n = (Node) nodeit.next(); - - // filter out nodes which are known to be in the result - if (n.isInResult()) - continue; - // if an incident edge is in the result, then the node coordinate is included already - if (n.isIncidentEdgeInResult()) - continue; - if (n.getEdges().getDegree() == 0 || opCode == OverlayOp.INTERSECTION) { - - /** - * For nodes on edges, only INTERSECTION can result in edge nodes being included even - * if none of their incident edges are included - */ - Label label = n.getLabel(); - if (OverlayOp.isResultOfOp(label, opCode)) { - filterCoveredNodeToPoint(n); - } - } - } - //System.out.println("connectedResultNodes collected = " + connectedResultNodes.size()); - } - - /** - * Converts non-covered nodes to Point objects and adds them to the result. - * - * A node is covered if it is contained in another element Geometry - * with higher dimension (e.g. a node point might be contained in a polygon, - * in which case the point can be eliminated from the result). - * - * @param n the node to test - */ - private void filterCoveredNodeToPoint(Node n) - { - Coordinate coord = n.getCoordinate(); - if (! op.isCoveredByLA(coord)) { - Point pt = geometryFactory.createPoint(coord); - resultPointList.add(pt); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java b/src/main/java/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java deleted file mode 100644 index 493e850ec7..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.*; - -/** - * Forms {@link Polygon}s out of a graph of {@link DirectedEdge}s. - * The edges to use are marked as being in the result Area. - *

                      - * - * @version 1.7 - */ -public class PolygonBuilder { - - private GeometryFactory geometryFactory; - //private List dirEdgeList; - //private NodeMap nodes; - private List shellList = new ArrayList(); - - public PolygonBuilder(GeometryFactory geometryFactory) - { - this.geometryFactory = geometryFactory; - } - - /** - * Add a complete graph. - * The graph is assumed to contain one or more polygons, - * possibly with holes. - */ - public void add(PlanarGraph graph) - { - add(graph.getEdgeEnds(), graph.getNodes()); - } - - /** - * Add a set of edges and nodes, which form a graph. - * The graph is assumed to contain one or more polygons, - * possibly with holes. - */ - public void add(Collection dirEdges, Collection nodes) - { - PlanarGraph.linkResultDirectedEdges(nodes); - List maxEdgeRings = buildMaximalEdgeRings(dirEdges); - List freeHoleList = new ArrayList(); - List edgeRings = buildMinimalEdgeRings(maxEdgeRings, shellList, freeHoleList); - sortShellsAndHoles(edgeRings, shellList, freeHoleList); - placeFreeHoles(shellList, freeHoleList); - //Assert: every hole on freeHoleList has a shell assigned to it - } - - public List getPolygons() - { - List resultPolyList = computePolygons(shellList); - return resultPolyList; - } - - - /** - * for all DirectedEdges in result, form them into MaximalEdgeRings - */ - private List buildMaximalEdgeRings(Collection dirEdges) - { - List maxEdgeRings = new ArrayList(); - for (Iterator it = dirEdges.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.isInResult() && de.getLabel().isArea() ) { - // if this edge has not yet been processed - if (de.getEdgeRing() == null) { - MaximalEdgeRing er = new MaximalEdgeRing(de, geometryFactory); - maxEdgeRings.add(er); - er.setInResult(); -//System.out.println("max node degree = " + er.getMaxDegree()); - } - } - } - return maxEdgeRings; - } - - private List buildMinimalEdgeRings(List maxEdgeRings, List shellList, List freeHoleList) - { - List edgeRings = new ArrayList(); - for (Iterator it = maxEdgeRings.iterator(); it.hasNext(); ) { - MaximalEdgeRing er = (MaximalEdgeRing) it.next(); - if (er.getMaxNodeDegree() > 2) { - er.linkDirectedEdgesForMinimalEdgeRings(); - List minEdgeRings = er.buildMinimalRings(); - // at this point we can go ahead and attempt to place holes, if this EdgeRing is a polygon - EdgeRing shell = findShell(minEdgeRings); - if (shell != null) { - placePolygonHoles(shell, minEdgeRings); - shellList.add(shell); - } - else { - freeHoleList.addAll(minEdgeRings); - } - } - else { - edgeRings.add(er); - } - } - return edgeRings; - } - - /** - * This method takes a list of MinimalEdgeRings derived from a MaximalEdgeRing, - * and tests whether they form a Polygon. This is the case if there is a single shell - * in the list. In this case the shell is returned. - * The other possibility is that they are a series of connected holes, in which case - * no shell is returned. - * - * @return the shell EdgeRing, if there is one - * or null, if all the rings are holes - */ - private EdgeRing findShell(List minEdgeRings) - { - int shellCount = 0; - EdgeRing shell = null; - for (Iterator it = minEdgeRings.iterator(); it.hasNext(); ) { - EdgeRing er = (MinimalEdgeRing) it.next(); - if (! er.isHole()) { - shell = er; - shellCount++; - } - } - Assert.isTrue(shellCount <= 1, "found two shells in MinimalEdgeRing list"); - return shell; - } - /** - * This method assigns the holes for a Polygon (formed from a list of - * MinimalEdgeRings) to its shell. - * Determining the holes for a MinimalEdgeRing polygon serves two purposes: - *

                        - *
                      • it is faster than using a point-in-polygon check later on. - *
                      • it ensures correctness, since if the PIP test was used the point - * chosen might lie on the shell, which might return an incorrect result from the - * PIP test - *
                      - */ - private void placePolygonHoles(EdgeRing shell, List minEdgeRings) - { - for (Iterator it = minEdgeRings.iterator(); it.hasNext(); ) { - MinimalEdgeRing er = (MinimalEdgeRing) it.next(); - if (er.isHole()) { - er.setShell(shell); - } - } - } - /** - * For all rings in the input list, - * determine whether the ring is a shell or a hole - * and add it to the appropriate list. - * Due to the way the DirectedEdges were linked, - * a ring is a shell if it is oriented CW, a hole otherwise. - */ - private void sortShellsAndHoles(List edgeRings, List shellList, List freeHoleList) - { - for (Iterator it = edgeRings.iterator(); it.hasNext(); ) { - EdgeRing er = (EdgeRing) it.next(); -// er.setInResult(); - if (er.isHole() ) { - freeHoleList.add(er); - } - else { - shellList.add(er); - } - } - } - /** - * This method determines finds a containing shell for all holes - * which have not yet been assigned to a shell. - * These "free" holes should - * all be properly contained in their parent shells, so it is safe to use the - * findEdgeRingContaining method. - * (This is the case because any holes which are NOT - * properly contained (i.e. are connected to their - * parent shell) would have formed part of a MaximalEdgeRing - * and been handled in a previous step). - * - * @throws TopologyException if a hole cannot be assigned to a shell - */ - private void placeFreeHoles(List shellList, List freeHoleList) - { - for (Iterator it = freeHoleList.iterator(); it.hasNext(); ) { - EdgeRing hole = (EdgeRing) it.next(); - // only place this hole if it doesn't yet have a shell - if (hole.getShell() == null) { - EdgeRing shell = findEdgeRingContaining(hole, shellList); - if (shell == null) - throw new TopologyException("unable to assign hole to a shell", hole.getCoordinate(0)); -// Assert.isTrue(shell != null, "unable to assign hole to a shell"); - hole.setShell(shell); - } - } - } - - /** - * Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. - * The innermost enclosing ring is the smallest enclosing ring. - * The algorithm used depends on the fact that: - *
                      - * ring A contains ring B iff envelope(ring A) contains envelope(ring B) - *
                      - * This routine is only safe to use if the chosen point of the hole - * is known to be properly contained in a shell - * (which is guaranteed to be the case if the hole does not touch its shell) - * - * @return containing EdgeRing, if there is one - * or null if no containing EdgeRing is found - */ - private EdgeRing findEdgeRingContaining(EdgeRing testEr, List shellList) - { - LinearRing testRing = testEr.getLinearRing(); - Envelope testEnv = testRing.getEnvelopeInternal(); - Coordinate testPt = testRing.getCoordinateN(0); - - EdgeRing minShell = null; - Envelope minEnv = null; - for (Iterator it = shellList.iterator(); it.hasNext(); ) { - EdgeRing tryShell = (EdgeRing) it.next(); - LinearRing tryRing = tryShell.getLinearRing(); - Envelope tryEnv = tryRing.getEnvelopeInternal(); - if (minShell != null) minEnv = minShell.getLinearRing().getEnvelopeInternal(); - boolean isContained = false; - if (tryEnv.contains(testEnv) - && CGAlgorithms.isPointInRing(testPt, tryRing.getCoordinates()) ) - isContained = true; - // check if this new containing ring is smaller than the current minimum ring - if (isContained) { - if (minShell == null - || minEnv.contains(tryEnv)) { - minShell = tryShell; - } - } - } - return minShell; - } - private List computePolygons(List shellList) - { - List resultPolyList = new ArrayList(); - // add Polygons for all shells - for (Iterator it = shellList.iterator(); it.hasNext(); ) { - EdgeRing er = (EdgeRing) it.next(); - Polygon poly = er.toPolygon(geometryFactory); - resultPolyList.add(poly); - } - return resultPolyList; - } - - /** - * Checks the current set of shells (with their associated holes) to - * see if any of them contain the point. - */ - public boolean containsPoint(Coordinate p) - { - for (Iterator it = shellList.iterator(); it.hasNext(); ) { - EdgeRing er = (EdgeRing) it.next(); - if (er.containsPoint(p)) - return true; - } - return false; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java b/src/main/java/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java deleted file mode 100644 index 5c7f2f5b4d..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java +++ /dev/null @@ -1,276 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.snap; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.GeometryTransformer; - -/** - * Snaps the vertices and segments of a {@link Geometry} - * to another Geometry's vertices. - * A snap distance tolerance is used to control where snapping is performed. - * Snapping one geometry to another can improve - * robustness for overlay operations by eliminating - * nearly-coincident edges - * (which cause problems during noding and intersection calculation). - * It can also be used to eliminate artifacts such as narrow slivers, spikes and gores. - *

                      - * Too much snapping can result in invalid topology - * being created, so the number and location of snapped vertices - * is decided using heuristics to determine when it - * is safe to snap. - * This can result in some potential snaps being omitted, however. - * - * @author Martin Davis - * @version 1.7 - */ -public class GeometrySnapper -{ - private static final double SNAP_PRECISION_FACTOR = 1e-9; - - /** - * Estimates the snap tolerance for a Geometry, taking into account its precision model. - * - * @param g a Geometry - * @return the estimated snap tolerance - */ - public static double computeOverlaySnapTolerance(Geometry g) - { - double snapTolerance = computeSizeBasedSnapTolerance(g); - - /** - * Overlay is carried out in the precision model - * of the two inputs. - * If this precision model is of type FIXED, then the snap tolerance - * must reflect the precision grid size. - * Specifically, the snap tolerance should be at least - * the distance from a corner of a precision grid cell - * to the centre point of the cell. - */ - PrecisionModel pm = g.getPrecisionModel(); - if (pm.getType() == PrecisionModel.FIXED) { - double fixedSnapTol = (1 / pm.getScale()) * 2 / 1.415; - if (fixedSnapTol > snapTolerance) - snapTolerance = fixedSnapTol; - } - return snapTolerance; - } - - public static double computeSizeBasedSnapTolerance(Geometry g) - { - Envelope env = g.getEnvelopeInternal(); - double minDimension = Math.min(env.getHeight(), env.getWidth()); - double snapTol = minDimension * SNAP_PRECISION_FACTOR; - return snapTol; - } - - public static double computeOverlaySnapTolerance(Geometry g0, Geometry g1) - { - return Math.min(computeOverlaySnapTolerance(g0), computeOverlaySnapTolerance(g1)); - } - - /** - * Snaps two geometries together with a given tolerance. - * - * @param g0 a geometry to snap - * @param g1 a geometry to snap - * @param snapTolerance the tolerance to use - * @return the snapped geometries - */ - public static Geometry[] snap(Geometry g0, Geometry g1, double snapTolerance) - { - Geometry[] snapGeom = new Geometry[2]; - GeometrySnapper snapper0 = new GeometrySnapper(g0); - snapGeom[0] = snapper0.snapTo(g1, snapTolerance); - - /** - * Snap the second geometry to the snapped first geometry - * (this strategy minimizes the number of possible different points in the result) - */ - GeometrySnapper snapper1 = new GeometrySnapper(g1); - snapGeom[1] = snapper1.snapTo(snapGeom[0], snapTolerance); - -// System.out.println(snap[0]); -// System.out.println(snap[1]); - return snapGeom; - } - /** - * Snaps a geometry to itself. - * Allows optionally cleaning the result to ensure it is - * topologically valid - * (which fixes issues such as topology collapses in polygonal inputs). - *

                      - * Snapping a geometry to itself can remove artifacts such as very narrow slivers, gores and spikes. - * - *@param geom the geometry to snap - *@param snapTolerance the snapping tolerance - *@param cleanResult whether the result should be made valid - * @return a new snapped Geometry - */ - public static Geometry snapToSelf(Geometry geom, double snapTolerance, boolean cleanResult) - { - GeometrySnapper snapper0 = new GeometrySnapper(geom); - return snapper0.snapToSelf(snapTolerance, cleanResult); - } - - private Geometry srcGeom; - - /** - * Creates a new snapper acting on the given geometry - * - * @param srcGeom the geometry to snap - */ - public GeometrySnapper(Geometry srcGeom) - { - this.srcGeom = srcGeom; - } - - - /** - * Snaps the vertices in the component {@link LineString}s - * of the source geometry - * to the vertices of the given snap geometry. - * - * @param snapGeom a geometry to snap the source to - * @return a new snapped Geometry - */ - public Geometry snapTo(Geometry snapGeom, double snapTolerance) - { - Coordinate[] snapPts = extractTargetCoordinates(snapGeom); - - SnapTransformer snapTrans = new SnapTransformer(snapTolerance, snapPts); - return snapTrans.transform(srcGeom); - } - - /** - * Snaps the vertices in the component {@link LineString}s - * of the source geometry - * to the vertices of the same geometry. - * Allows optionally cleaning the result to ensure it is - * topologically valid - * (which fixes issues such as topology collapses in polygonal inputs). - * - *@param snapTolerance the snapping tolerance - *@param cleanResult whether the result should be made valid - * @return a new snapped Geometry - */ - public Geometry snapToSelf(double snapTolerance, boolean cleanResult) - { - Coordinate[] snapPts = extractTargetCoordinates(srcGeom); - - SnapTransformer snapTrans = new SnapTransformer(snapTolerance, snapPts, true); - Geometry snappedGeom = snapTrans.transform(srcGeom); - Geometry result = snappedGeom; - if (cleanResult && result instanceof Polygonal) { - // TODO: use better cleaning approach - result = snappedGeom.buffer(0); - } - return result; - } - - private Coordinate[] extractTargetCoordinates(Geometry g) - { - // TODO: should do this more efficiently. Use CoordSeq filter to get points, KDTree for uniqueness & queries - Set ptSet = new TreeSet(); - Coordinate[] pts = g.getCoordinates(); - for (int i = 0; i < pts.length; i++) { - ptSet.add(pts[i]); - } - return (Coordinate[]) ptSet.toArray(new Coordinate[0]); - } - - /** - * Computes the snap tolerance based on the input geometries. - * - * @param ringPts - * @return - */ - private double computeSnapTolerance(Coordinate[] ringPts) - { - double minSegLen = computeMinimumSegmentLength(ringPts); - // use a small percentage of this to be safe - double snapTol = minSegLen / 10; - return snapTol; - } - - private double computeMinimumSegmentLength(Coordinate[] pts) - { - double minSegLen = Double.MAX_VALUE; - for (int i = 0; i < pts.length - 1; i++) { - double segLen = pts[i].distance(pts[i + 1]); - if (segLen < minSegLen) - minSegLen = segLen; - } - return minSegLen; - } - -} - -class SnapTransformer - extends GeometryTransformer -{ - private double snapTolerance; - private Coordinate[] snapPts; - private boolean isSelfSnap = false; - - SnapTransformer(double snapTolerance, Coordinate[] snapPts) - { - this.snapTolerance = snapTolerance; - this.snapPts = snapPts; - } - - SnapTransformer(double snapTolerance, Coordinate[] snapPts, boolean isSelfSnap) - { - this.snapTolerance = snapTolerance; - this.snapPts = snapPts; - this.isSelfSnap = isSelfSnap; - } - - protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) - { - Coordinate[] srcPts = coords.toCoordinateArray(); - Coordinate[] newPts = snapLine(srcPts, snapPts); - return factory.getCoordinateSequenceFactory().create(newPts); - } - - private Coordinate[] snapLine(Coordinate[] srcPts, Coordinate[] snapPts) - { - LineStringSnapper snapper = new LineStringSnapper(srcPts, snapTolerance); - snapper.setAllowSnappingToSourceVertices(isSelfSnap); - return snapper.snapTo(snapPts); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java b/src/main/java/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java deleted file mode 100644 index 08992ce26e..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java +++ /dev/null @@ -1,236 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.snap; - -import com.vividsolutions.jts.geom.*; - -/** - * Snaps the vertices and segments of a {@link LineString} - * to a set of target snap vertices. - * A snap distance tolerance is used to control where snapping is performed. - *

                      - * The implementation handles empty geometry and empty snap vertex sets. - * - * @author Martin Davis - * @version 1.7 - */ -public class LineStringSnapper -{ - private double snapTolerance = 0.0; - - private Coordinate[] srcPts; - private LineSegment seg = new LineSegment(); // for reuse during snapping - private boolean allowSnappingToSourceVertices = false; - private boolean isClosed = false; - - /** - * Creates a new snapper using the points in the given {@link LineString} - * as source snap points. - * - * @param srcLine a LineString to snap (may be empty) - * @param snapTolerance the snap tolerance to use - */ - public LineStringSnapper(LineString srcLine, double snapTolerance) - { - this(srcLine.getCoordinates(), snapTolerance); - } - - /** - * Creates a new snapper using the given points - * as source points to be snapped. - * - * @param srcPts the points to snap - * @param snapTolerance the snap tolerance to use - */ - public LineStringSnapper(Coordinate[] srcPts, double snapTolerance) - { - this.srcPts = srcPts; - isClosed = isClosed(srcPts); - this.snapTolerance = snapTolerance; - } - - public void setAllowSnappingToSourceVertices(boolean allowSnappingToSourceVertices) - { - this.allowSnappingToSourceVertices = allowSnappingToSourceVertices; - } - private static boolean isClosed(Coordinate[] pts) - { - if (pts.length <= 1) return false; - return pts[0].equals2D(pts[pts.length - 1]); - } - /** - * Snaps the vertices and segments of the source LineString - * to the given set of snap vertices. - * - * @param snapPts the vertices to snap to - * @return a list of the snapped points - */ - public Coordinate[] snapTo(Coordinate[] snapPts) - { - CoordinateList coordList = new CoordinateList(srcPts); - - snapVertices(coordList, snapPts); - snapSegments(coordList, snapPts); - - Coordinate[] newPts = coordList.toCoordinateArray(); - return newPts; - } - - /** - * Snap source vertices to vertices in the target. - * - * @param srcCoords the points to snap - * @param snapPts the points to snap to - */ - private void snapVertices(CoordinateList srcCoords, Coordinate[] snapPts) - { - // try snapping vertices - // if src is a ring then don't snap final vertex - int end = isClosed ? srcCoords.size() - 1 : srcCoords.size(); - for (int i = 0; i < end; i++) { - Coordinate srcPt = (Coordinate) srcCoords.get(i); - Coordinate snapVert = findSnapForVertex(srcPt, snapPts); - if (snapVert != null) { - // update src with snap pt - srcCoords.set(i, new Coordinate(snapVert)); - // keep final closing point in synch (rings only) - if (i == 0 && isClosed) - srcCoords.set(srcCoords.size() - 1, new Coordinate(snapVert)); - } - } - } - - private Coordinate findSnapForVertex(Coordinate pt, Coordinate[] snapPts) - { - for (int i = 0; i < snapPts.length; i++) { - // if point is already equal to a src pt, don't snap - if (pt.equals2D(snapPts[i])) - return null; - if (pt.distance(snapPts[i]) < snapTolerance) - return snapPts[i]; - } - return null; - } - - /** - * Snap segments of the source to nearby snap vertices. - * Source segments are "cracked" at a snap vertex. - * A single input segment may be snapped several times - * to different snap vertices. - *

                      - * For each distinct snap vertex, at most one source segment - * is snapped to. This prevents "cracking" multiple segments - * at the same point, which would likely cause - * topology collapse when being used on polygonal linework. - * - * @param srcCoords the coordinates of the source linestring to be snapped - * @param snapPts the target snap vertices - */ - private void snapSegments(CoordinateList srcCoords, Coordinate[] snapPts) - { - // guard against empty input - if (snapPts.length == 0) return; - - int distinctPtCount = snapPts.length; - - // check for duplicate snap pts when they are sourced from a linear ring. - // TODO: Need to do this better - need to check *all* snap points for dups (using a Set?) - if (snapPts[0].equals2D(snapPts[snapPts.length - 1])) - distinctPtCount = snapPts.length - 1; - - for (int i = 0; i < distinctPtCount; i++) { - Coordinate snapPt = snapPts[i]; - int index = findSegmentIndexToSnap(snapPt, srcCoords); - /** - * If a segment to snap to was found, "crack" it at the snap pt. - * The new pt is inserted immediately into the src segment list, - * so that subsequent snapping will take place on the modified segments. - * Duplicate points are not added. - */ - if (index >= 0) { - srcCoords.add(index + 1, new Coordinate(snapPt), false); - } - } - } - - - /** - * Finds a src segment which snaps to (is close to) the given snap point. - *

                      - * Only a single segment is selected for snapping. - * This prevents multiple segments snapping to the same snap vertex, - * which would almost certainly cause invalid geometry - * to be created. - * (The heuristic approach to snapping used here - * is really only appropriate when - * snap pts snap to a unique spot on the src geometry.) - *

                      - * Also, if the snap vertex occurs as a vertex in the src coordinate list, - * no snapping is performed. - * - * @param snapPt the point to snap to - * @param srcCoords the source segment coordinates - * @return the index of the snapped segment - * or -1 if no segment snaps to the snap point - */ - private int findSegmentIndexToSnap(Coordinate snapPt, CoordinateList srcCoords) - { - double minDist = Double.MAX_VALUE; - int snapIndex = -1; - for (int i = 0; i < srcCoords.size() - 1; i++) { - seg.p0 = (Coordinate) srcCoords.get(i); - seg.p1 = (Coordinate) srcCoords.get(i + 1); - - /** - * Check if the snap pt is equal to one of the segment endpoints. - * - * If the snap pt is already in the src list, don't snap at all. - */ - if (seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt)) { - if (allowSnappingToSourceVertices) - continue; - else - return -1; - } - - double dist = seg.distance(snapPt); - if (dist < snapTolerance && dist < minDist) { - minDist = dist; - snapIndex = i; - } - } - return snapIndex; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java b/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java deleted file mode 100644 index 121eebc972..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java +++ /dev/null @@ -1,124 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.snap; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.operation.overlay.OverlayOp; -import com.vividsolutions.jts.operation.overlay.validate.OverlayResultValidator; - - -/** - * Performs an overlay operation using snapping and enhanced precision - * to improve the robustness of the result. - * This class only uses snapping - * if an error is detected when running the standard JTS overlay code. - * Errors detected include thrown exceptions - * (in particular, {@link TopologyException}) - * and invalid overlay computations. - * - * @author Martin Davis - * @version 1.7 - */ -public class SnapIfNeededOverlayOp -{ - public static Geometry overlayOp(Geometry g0, Geometry g1, int opCode) - { - SnapIfNeededOverlayOp op = new SnapIfNeededOverlayOp(g0, g1); - return op.getResultGeometry(opCode); - } - - public static Geometry intersection(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.INTERSECTION); - } - - public static Geometry union(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.UNION); - } - - public static Geometry difference(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.DIFFERENCE); - } - - public static Geometry symDifference(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.SYMDIFFERENCE); - } - - private Geometry[] geom = new Geometry[2]; - - public SnapIfNeededOverlayOp(Geometry g1, Geometry g2) - { - geom[0] = g1; - geom[1] = g2; - } - - public Geometry getResultGeometry(int opCode) - { - Geometry result = null; - boolean isSuccess = false; - RuntimeException savedException = null; - try { - // try basic operation with input geometries - result = OverlayOp.overlayOp(geom[0], geom[1], opCode); - boolean isValid = true; - // not needed if noding validation is used -// boolean isValid = OverlayResultValidator.isValid(geom[0], geom[1], OverlayOp.INTERSECTION, result); - if (isValid) - isSuccess = true; - } - catch (RuntimeException ex) { - savedException = ex; - // ignore this exception, since the operation will be rerun -// System.out.println(ex.getMessage()); -// ex.printStackTrace(); - //System.out.println(ex.getMessage()); - //System.out.println("Geom 0: " + geom[0]); - //System.out.println("Geom 1: " + geom[1]); - } - if (! isSuccess) { - // this may still throw an exception - // if so, throw the original exception since it has the input coordinates - try { - result = SnapOverlayOp.overlayOp(geom[0], geom[1], opCode); - } - catch (RuntimeException ex) { - throw savedException; - } - } - return result; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java b/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java deleted file mode 100644 index e637bdac0f..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java +++ /dev/null @@ -1,159 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.snap; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.operation.overlay.OverlayOp; -import com.vividsolutions.jts.precision.CommonBitsRemover; - -/** - * Performs an overlay operation using snapping and enhanced precision - * to improve the robustness of the result. - * This class always uses snapping. - * This is less performant than the standard JTS overlay code, - * and may even introduce errors which were not present in the original data. - * For this reason, this class should only be used - * if the standard overlay code fails to produce a correct result. - * - * @author Martin Davis - * @version 1.7 - */ -public class SnapOverlayOp -{ - public static Geometry overlayOp(Geometry g0, Geometry g1, int opCode) - { - SnapOverlayOp op = new SnapOverlayOp(g0, g1); - return op.getResultGeometry(opCode); - } - - public static Geometry intersection(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.INTERSECTION); - } - - public static Geometry union(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.UNION); - } - - public static Geometry difference(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.DIFFERENCE); - } - - public static Geometry symDifference(Geometry g0, Geometry g1) - { - return overlayOp(g0, g1, OverlayOp.SYMDIFFERENCE); - } - - - private Geometry[] geom = new Geometry[2]; - private double snapTolerance; - - public SnapOverlayOp(Geometry g1, Geometry g2) - { - geom[0] = g1; - geom[1] = g2; - computeSnapTolerance(); - } - private void computeSnapTolerance() - { - snapTolerance = GeometrySnapper.computeOverlaySnapTolerance(geom[0], geom[1]); - - // System.out.println("Snap tol = " + snapTolerance); - } - - public Geometry getResultGeometry(int opCode) - { -// Geometry[] selfSnapGeom = new Geometry[] { selfSnap(geom[0]), selfSnap(geom[1])}; - Geometry[] prepGeom = snap(geom); - Geometry result = OverlayOp.overlayOp(prepGeom[0], prepGeom[1], opCode); - return prepareResult(result); - } - - private Geometry selfSnap(Geometry geom) - { - GeometrySnapper snapper0 = new GeometrySnapper(geom); - Geometry snapGeom = snapper0.snapTo(geom, snapTolerance); - //System.out.println("Self-snapped: " + snapGeom); - //System.out.println(); - return snapGeom; - } - - private Geometry[] snap(Geometry[] geom) - { - Geometry[] remGeom = removeCommonBits(geom); - - // MD - testing only -// Geometry[] remGeom = geom; - - Geometry[] snapGeom = GeometrySnapper.snap(remGeom[0], remGeom[1], snapTolerance); - // MD - may want to do this at some point, but it adds cycles -// checkValid(snapGeom[0]); -// checkValid(snapGeom[1]); - - /* - System.out.println("Snapped geoms: "); - System.out.println(snapGeom[0]); - System.out.println(snapGeom[1]); - */ - return snapGeom; - } - - private Geometry prepareResult(Geometry geom) - { - cbr.addCommonBits(geom); - return geom; - } - - private CommonBitsRemover cbr; - - private Geometry[] removeCommonBits(Geometry[] geom) - { - cbr = new CommonBitsRemover(); - cbr.add(geom[0]); - cbr.add(geom[1]); - Geometry remGeom[] = new Geometry[2]; - remGeom[0] = cbr.removeCommonBits((Geometry) geom[0].clone()); - remGeom[1] = cbr.removeCommonBits((Geometry) geom[1].clone()); - return remGeom; - } - - private void checkValid(Geometry g) - { - if (! g.isValid()) { - System.out.println("Snapped geometry is invalid"); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/FuzzyPointLocator.java b/src/main/java/com/vividsolutions/jts/operation/overlay/validate/FuzzyPointLocator.java deleted file mode 100644 index ceec35304f..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/FuzzyPointLocator.java +++ /dev/null @@ -1,151 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.validate; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; - -/** - * Finds the most likely {@link Location} of a point relative to - * the polygonal components of a geometry, using a tolerance value. - * If a point is not clearly in the Interior or Exterior, - * it is considered to be on the Boundary. - * In other words, if the point is within the tolerance of the Boundary, - * it is considered to be on the Boundary; otherwise, - * whether it is Interior or Exterior is determined directly. - * - * @author Martin Davis - * @version 1.7 - */ -public class FuzzyPointLocator -{ - private Geometry g; - private double boundaryDistanceTolerance; - private MultiLineString linework; - private PointLocator ptLocator = new PointLocator(); - private LineSegment seg = new LineSegment(); - - public FuzzyPointLocator(Geometry g, double boundaryDistanceTolerance) - { - this.g = g; - this.boundaryDistanceTolerance = boundaryDistanceTolerance; - linework = extractLinework(g); - } - - public int getLocation(Coordinate pt) - { - if (isWithinToleranceOfBoundary(pt)) - return Location.BOUNDARY; - /* - double dist = linework.distance(point); - - // if point is close to boundary, it is considered to be on the boundary - if (dist < tolerance) - return Location.BOUNDARY; - */ - - // now we know point must be clearly inside or outside geometry, so return actual location value - return ptLocator.locate(pt, g); - } - - /** - * Extracts linework for polygonal components. - * - * @param g the geometry from which to extract - * @return a lineal geometry containing the extracted linework - */ - private MultiLineString extractLinework(Geometry g) - { - PolygonalLineworkExtracter extracter = new PolygonalLineworkExtracter(); - g.apply(extracter); - List linework = extracter.getLinework(); - LineString[] lines = GeometryFactory.toLineStringArray(linework); - return g.getFactory().createMultiLineString(lines); - } - - private boolean isWithinToleranceOfBoundary(Coordinate pt) - { - for (int i = 0; i < linework.getNumGeometries(); i++) { - LineString line = (LineString) linework.getGeometryN(i); - CoordinateSequence seq = line.getCoordinateSequence(); - for (int j = 0; j < seq.size() - 1; j++) { - seq.getCoordinate(j, seg.p0); - seq.getCoordinate(j + 1, seg.p1); - double dist = seg.distance(pt); - if (dist <= boundaryDistanceTolerance) - return true; - } - } - return false; - } -} - -/** - * Extracts the LineStrings in the boundaries - * of all the polygonal elements in the target {@link Geometry}. - * - * @author Martin Davis - */ -class PolygonalLineworkExtracter - implements GeometryFilter -{ - private List linework; - - public PolygonalLineworkExtracter() - { - linework = new ArrayList(); - } - - /** - * Filters out all linework for polygonal elements - */ - public void filter(Geometry g) - { - if (g instanceof Polygon) { - Polygon poly = (Polygon) g; - linework.add(poly.getExteriorRing()); - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - linework.add(poly.getInteriorRingN(i)); - } - } - } - - /** - * Gets the list of polygonal linework. - * - * @return a List of LineStrings - */ - public List getLinework() { return linework; } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OffsetPointGenerator.java b/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OffsetPointGenerator.java deleted file mode 100644 index 4c20bae968..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OffsetPointGenerator.java +++ /dev/null @@ -1,133 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.overlay.validate; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Generates points offset by a given distance - * from both sides of the midpoint of - * all segments in a {@link Geometry}. - * Can be used to generate probe points for - * determining whether a polygonal overlay result - * is incorrect. - * The input geometry may have any orientation for its rings, - * but {@link #setSidesToGenerate(boolean, boolean)} is - * only meaningful if the orientation is known. - * - * @author Martin Davis - * @version 1.7 - */ -public class OffsetPointGenerator -{ - private Geometry g; - private boolean doLeft = true; - private boolean doRight = true; - - public OffsetPointGenerator(Geometry g) - { - this.g = g; - } - - /** - * Set the sides on which to generate offset points. - * - * @param doLeft - * @param doRight - */ - public void setSidesToGenerate(boolean doLeft, boolean doRight) - { - this.doLeft = doLeft; - this.doRight = doRight; - } - - /** - * Gets the computed offset points. - * - * @return List - */ - public List getPoints(double offsetDistance) - { - List offsetPts = new ArrayList(); - List lines = LinearComponentExtracter.getLines(g); - for (Iterator i = lines.iterator(); i.hasNext(); ) { - LineString line = (LineString) i.next(); - extractPoints(line, offsetDistance, offsetPts); - } - //System.out.println(toMultiPoint(offsetPts)); - return offsetPts; - } - - private void extractPoints(LineString line, double offsetDistance, List offsetPts) - { - Coordinate[] pts = line.getCoordinates(); - for (int i = 0; i < pts.length - 1; i++) { - computeOffsetPoints(pts[i], pts[i + 1], offsetDistance, offsetPts); - } - } - - /** - * Generates the two points which are offset from the - * midpoint of the segment (p0, p1) by the - * offsetDistance. - * - * @param p0 the first point of the segment to offset from - * @param p1 the second point of the segment to offset from - */ - private void computeOffsetPoints(Coordinate p0, Coordinate p1, double offsetDistance, List offsetPts) - { - double dx = p1.x - p0.x; - double dy = p1.y - p0.y; - double len = Math.sqrt(dx * dx + dy * dy); - // u is the vector that is the length of the offset, in the direction of the segment - double ux = offsetDistance * dx / len; - double uy = offsetDistance * dy / len; - - double midX = (p1.x + p0.x) / 2; - double midY = (p1.y + p0.y) / 2; - - if (doLeft) { - Coordinate offsetLeft = new Coordinate(midX - uy, midY + ux); - offsetPts.add(offsetLeft); - } - - if (doRight) { - Coordinate offsetRight = new Coordinate(midX + uy, midY - ux); - offsetPts.add(offsetRight); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OverlayResultValidator.java b/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OverlayResultValidator.java deleted file mode 100644 index 3b15e07cbd..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/overlay/validate/OverlayResultValidator.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.overlay.validate; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.operation.overlay.OverlayOp; -import com.vividsolutions.jts.operation.overlay.snap.GeometrySnapper; - -/** - * Validates that the result of an overlay operation is - * geometrically correct, within a determined tolerance. - * Uses fuzzy point location to find points which are - * definitely in either the interior or exterior of the result - * geometry, and compares these results with the expected ones. - *

                      - * This algorithm is only useful where the inputs are polygonal. - * This is a heuristic test, and may return false positive results - * (I.e. it may fail to detect an invalid result.) - * It should never return a false negative result, however - * (I.e. it should never report a valid result as invalid.) - * - * @author Martin Davis - * @version 1.7 - * @see OverlayOp - */ -public class OverlayResultValidator -{ - public static boolean isValid(Geometry a, Geometry b, int overlayOp, Geometry result) - { - OverlayResultValidator validator = new OverlayResultValidator(a, b, result); - return validator.isValid(overlayOp); - } - - private static double computeBoundaryDistanceTolerance(Geometry g0, Geometry g1) - { - return Math.min(GeometrySnapper.computeSizeBasedSnapTolerance(g0), - GeometrySnapper.computeSizeBasedSnapTolerance(g1)); - } - - private static final double TOLERANCE = 0.000001; - - private Geometry[] geom; - private FuzzyPointLocator[] locFinder; - private int[] location = new int[3] ; - private Coordinate invalidLocation = null; - private double boundaryDistanceTolerance = TOLERANCE; - - private List testCoords = new ArrayList(); - - public OverlayResultValidator(Geometry a, Geometry b, Geometry result) - { - /** - * The tolerance to use needs to depend on the size of the geometries. - * It should not be more precise than double-precision can support. - */ - boundaryDistanceTolerance = computeBoundaryDistanceTolerance(a, b); - geom = new Geometry[] { a, b, result }; - locFinder = new FuzzyPointLocator[] { - new FuzzyPointLocator(geom[0], boundaryDistanceTolerance), - new FuzzyPointLocator(geom[1], boundaryDistanceTolerance), - new FuzzyPointLocator(geom[2], boundaryDistanceTolerance) - }; - } - - public boolean isValid(int overlayOp) - { - addTestPts(geom[0]); - addTestPts(geom[1]); - boolean isValid = checkValid(overlayOp); - - /* - System.out.println("OverlayResultValidator: " + isValid); - System.out.println("G0"); - System.out.println(geom[0]); - System.out.println("G1"); - System.out.println(geom[1]); - System.out.println("Result"); - System.out.println(geom[2]); - */ - - return isValid; - } - - public Coordinate getInvalidLocation() { return invalidLocation; } - - private void addTestPts(Geometry g) - { - OffsetPointGenerator ptGen = new OffsetPointGenerator(g); - testCoords.addAll(ptGen.getPoints(5 * boundaryDistanceTolerance)); - } - - private boolean checkValid(int overlayOp) - { - for (int i = 0; i < testCoords.size(); i++) { - Coordinate pt = (Coordinate) testCoords.get(i); - if (! checkValid(overlayOp, pt)) { - invalidLocation = pt; - return false; - } - } - return true; - } - - private boolean checkValid(int overlayOp, Coordinate pt) - { - location[0] = locFinder[0].getLocation(pt); - location[1] = locFinder[1].getLocation(pt); - location[2] = locFinder[2].getLocation(pt); - - /** - * If any location is on the Boundary, can't deduce anything, so just return true - */ - if (hasLocation(location, Location.BOUNDARY)) - return true; - - return isValidResult(overlayOp, location); - } - - private static boolean hasLocation(int[] location, int loc) - { - for (int i = 0; i < 3; i ++) { - if (location[i] == loc) - return true; - } - return false; - } - - private boolean isValidResult(int overlayOp, int[] location) - { - boolean expectedInterior = OverlayOp.isResultOfOp(location[0], location[1], overlayOp); - - boolean resultInInterior = (location[2] == Location.INTERIOR); - // MD use simpler: boolean isValid = (expectedInterior == resultInInterior); - boolean isValid = ! (expectedInterior ^ resultInInterior); - - if (! isValid) reportResult(overlayOp, location, expectedInterior); - - return isValid; - } - - private void reportResult(int overlayOp, int[] location, boolean expectedInterior) - { - System.out.println( - "Overlay result invalid - A:" + Location.toLocationSymbol(location[0]) - + " B:" + Location.toLocationSymbol(location[1]) - + " expected:" + (expectedInterior ? 'i' : 'e') - + " actual:" + Location.toLocationSymbol(location[2]) - ); - } -} - diff --git a/src/main/java/com/vividsolutions/jts/operation/polygonize/EdgeRing.java b/src/main/java/com/vividsolutions/jts/operation/polygonize/EdgeRing.java deleted file mode 100644 index 72be78a563..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/polygonize/EdgeRing.java +++ /dev/null @@ -1,476 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - - -package com.vividsolutions.jts.operation.polygonize; - -import java.util.*; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; -import com.vividsolutions.jts.io.WKTWriter; -import com.vividsolutions.jts.planargraph.*; -import com.vividsolutions.jts.util.Assert; - -/** - * Represents a ring of {@link PolygonizeDirectedEdge}s which form - * a ring of a polygon. The ring may be either an outer shell or a hole. - * - * @version 1.7 - */ -class EdgeRing { - - /** - * Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. - * The innermost enclosing ring is the smallest enclosing ring. - * The algorithm used depends on the fact that: - *
                      - * ring A contains ring B iff envelope(ring A) contains envelope(ring B) - *
                      - * This routine is only safe to use if the chosen point of the hole - * is known to be properly contained in a shell - * (which is guaranteed to be the case if the hole does not touch its shell) - * - * @return containing EdgeRing, if there is one - * or null if no containing EdgeRing is found - */ - public static EdgeRing findEdgeRingContaining(EdgeRing testEr, List shellList) - { - LinearRing testRing = testEr.getRing(); - Envelope testEnv = testRing.getEnvelopeInternal(); - Coordinate testPt = testRing.getCoordinateN(0); - - EdgeRing minShell = null; - Envelope minShellEnv = null; - for (Iterator it = shellList.iterator(); it.hasNext(); ) { - EdgeRing tryShell = (EdgeRing) it.next(); - LinearRing tryShellRing = tryShell.getRing(); - Envelope tryShellEnv = tryShellRing.getEnvelopeInternal(); - // the hole envelope cannot equal the shell envelope - // (also guards against testing rings against themselves) - if (tryShellEnv.equals(testEnv)) continue; - // hole must be contained in shell - if (! tryShellEnv.contains(testEnv)) continue; - - testPt = CoordinateArrays.ptNotInList(testRing.getCoordinates(), tryShellRing.getCoordinates()); - boolean isContained = false; - if (CGAlgorithms.isPointInRing(testPt, tryShellRing.getCoordinates()) ) - isContained = true; - - // check if this new containing ring is smaller than the current minimum ring - if (isContained) { - if (minShell == null - || minShellEnv.contains(tryShellEnv)) { - minShell = tryShell; - minShellEnv = minShell.getRing().getEnvelopeInternal(); - } - } - } - return minShell; - } - - /** - * Finds a point in a list of points which is not contained in another list of points - * @param testPts the {@link Coordinate}s to test - * @param pts an array of {@link Coordinate}s to test the input points against - * @return a {@link Coordinate} from testPts which is not in pts, - * or null if there is no coordinate not in the list - * - * @deprecated Use CoordinateArrays.ptNotInList instead - */ - public static Coordinate ptNotInList(Coordinate[] testPts, Coordinate[] pts) - { - for (int i = 0; i < testPts.length; i++) { - Coordinate testPt = testPts[i]; - if (! isInList(testPt, pts)) - return testPt; - } - return null; - } - - /** - * Tests whether a given point is in an array of points. - * Uses a value-based test. - * - * @param pt a {@link Coordinate} for the test point - * @param pts an array of {@link Coordinate}s to test - * @return true if the point is in the array - * - * @deprecated - */ - public static boolean isInList(Coordinate pt, Coordinate[] pts) - { - for (int i = 0; i < pts.length; i++) { - if (pt.equals(pts[i])) - return true; - } - return false; - } - - /** - * Traverses a ring of DirectedEdges, accumulating them into a list. - * This assumes that all dangling directed edges have been removed - * from the graph, so that there is always a next dirEdge. - * - * @param startDE the DirectedEdge to start traversing at - * @return a List of DirectedEdges that form a ring - */ - public static List findDirEdgesInRing(PolygonizeDirectedEdge startDE) - { - PolygonizeDirectedEdge de = startDE; - List edges = new ArrayList(); - do { - edges.add(de); - de = de.getNext(); - Assert.isTrue(de != null, "found null DE in ring"); - Assert.isTrue(de == startDE || ! de.isInRing(), "found DE already in ring"); - } while (de != startDE); - return edges; - } - - private GeometryFactory factory; - - private List deList = new ArrayList(); - private DirectedEdge lowestEdge = null; - - // cache the following data for efficiency - private LinearRing ring = null; - - private Coordinate[] ringPts = null; - private List holes; - private EdgeRing shell; - private boolean isHole; - private boolean isProcessed = false; - private boolean isIncludedSet = false; - private boolean isIncluded = false; - - public EdgeRing(GeometryFactory factory) - { - this.factory = factory; - } - - public void build(PolygonizeDirectedEdge startDE) { - PolygonizeDirectedEdge de = startDE; - do { - add(de); - de.setRing(this); - de = de.getNext(); - Assert.isTrue(de != null, "found null DE in ring"); - Assert.isTrue(de == startDE || ! de.isInRing(), "found DE already in ring"); - } while (de != startDE); - } - - /** - * Adds a {@link DirectedEdge} which is known to form part of this ring. - * @param de the {@link DirectedEdge} to add. - */ - private void add(DirectedEdge de) - { - deList.add(de); - } - - /** - * Tests whether this ring is a hole. - * @return true if this ring is a hole - */ - public boolean isHole() - { - return isHole; - } - - /** - * Computes whether this ring is a hole. - * Due to the way the edges in the polyongization graph are linked, - * a ring is a hole if it is oriented counter-clockwise. - */ - public void computeHole() - { - LinearRing ring = getRing(); - isHole = CGAlgorithms.isCCW(ring.getCoordinates()); - } - - /** - * Adds a hole to the polygon formed by this ring. - * @param hole the {@link LinearRing} forming the hole. - */ - public void addHole(LinearRing hole) { - if (holes == null) - holes = new ArrayList(); - holes.add(hole); - } - - /** - * Adds a hole to the polygon formed by this ring. - * @param hole the {@link LinearRing} forming the hole. - */ - public void addHole(EdgeRing holeER) { - holeER.setShell(this); - LinearRing hole = holeER.getRing(); - if (holes == null) - holes = new ArrayList(); - holes.add(hole); - } - - /** - * Computes the {@link Polygon} formed by this ring and any contained holes. - * - * @return the {@link Polygon} formed by this ring and its holes. - */ - public Polygon getPolygon() - { - LinearRing[] holeLR = null; - if (holes != null) { - holeLR = new LinearRing[holes.size()]; - for (int i = 0; i < holes.size(); i++) { - holeLR[i] = (LinearRing) holes.get(i); - } - } - Polygon poly = factory.createPolygon(ring, holeLR); - return poly; - } - - /** - * Tests if the {@link LinearRing} ring formed by this edge ring is topologically valid. - * - * @return true if the ring is valid - */ - public boolean isValid() - { - getCoordinates(); - if (ringPts.length <= 3) return false; - getRing(); - return ring.isValid(); - } - - public boolean isIncludedSet() { - return isIncludedSet; - } - - public boolean isIncluded() { - return isIncluded; - } - - public void setIncluded(boolean isIncluded) { - this.isIncluded = isIncluded; - this.isIncludedSet = true; - } - - /** - * Computes the list of coordinates which are contained in this ring. - * The coordinatea are computed once only and cached. - * - * @return an array of the {@link Coordinate}s in this ring - */ - private Coordinate[] getCoordinates() - { - if (ringPts == null) { - CoordinateList coordList = new CoordinateList(); - for (Iterator i = deList.iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - PolygonizeEdge edge = (PolygonizeEdge) de.getEdge(); - addEdge(edge.getLine().getCoordinates(), de.getEdgeDirection(), coordList); - } - ringPts = coordList.toCoordinateArray(); - } - return ringPts; - } - - /** - * Gets the coordinates for this ring as a {@link LineString}. - * Used to return the coordinates in this ring - * as a valid geometry, when it has been detected that the ring is topologically - * invalid. - * @return a {@link LineString} containing the coordinates in this ring - */ - public LineString getLineString() - { - getCoordinates(); - return factory.createLineString(ringPts); - } - - /** - * Returns this ring as a {@link LinearRing}, or null if an Exception occurs while - * creating it (such as a topology problem). Details of problems are written to - * standard output. - */ - public LinearRing getRing() - { - if (ring != null) return ring; - getCoordinates(); - if (ringPts.length < 3) System.out.println(ringPts); - try { - ring = factory.createLinearRing(ringPts); - } - catch (Exception ex) { - System.out.println(ringPts); - } - return ring; - } - - private static void addEdge(Coordinate[] coords, boolean isForward, CoordinateList coordList) - { - if (isForward) { - for (int i = 0; i < coords.length; i++) { - coordList.add(coords[i], false); - } - } - else { - for (int i = coords.length - 1; i >= 0; i--) { - coordList.add(coords[i], false); - } - } - } - - /** - * Sets the containing shell ring of a ring that has been determined to be a hole. - * - * @param shell the shell ring - */ - public void setShell(EdgeRing shell) { - this.shell = shell; - } - - /** - * Tests whether this ring has a shell assigned to it. - * - * @return true if the ring has a shell - */ - public boolean hasShell() { - return shell != null; - } - - /** - * Gets the shell for this ring. The shell is the ring itself if it is not a hole, otherwise its parent shell. - * - * @return the shell for this ring - */ - public EdgeRing getShell() { - if (isHole()) return shell; - return this; - } - /** - * Tests whether this ring is an outer hole. - * A hole is an outer hole if it is not contained by a shell. - * - * @return true if the ring is an outer hole. - */ - public boolean isOuterHole() { - if (! isHole) return false; - return ! hasShell(); - } - - /** - * Tests whether this ring is an outer shell. - * - * @return true if the ring is an outer shell. - */ - public boolean isOuterShell() { - return getOuterHole() != null; - } - - public EdgeRing getOuterHole() - { - if (isHole()) return null; - /* - * A shell is an outer shell if any edge is also in an outer hole. - * A hole is an outer hole if it is not contained by a shell. - */ - for (int i = 0; i < deList.size(); i++) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) deList.get(i); - EdgeRing adjRing = ((PolygonizeDirectedEdge) de.getSym()).getRing(); - if (adjRing.isOuterHole()) return adjRing; - } - return null; - } - - /** - * Updates the included status for currently non-included shells - * based on whether they are adjacent to an included shell. - */ - public void updateIncluded() { - if (isHole()) return; - for (int i = 0; i < deList.size(); i++) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) deList.get(i); - EdgeRing adjShell = ((PolygonizeDirectedEdge) de.getSym()).getRing().getShell(); - - if (adjShell != null && adjShell.isIncludedSet()) { - // adjacent ring has been processed, so set included to inverse of adjacent included - setIncluded(! adjShell.isIncluded()); - return; - } - } - } - - /** - * Gets a string representation of this object. - * - * @return a string representing the object - */ - public String toString() { - return WKTWriter.toLineString(new CoordinateArraySequence(getCoordinates())); - } - - /** - * @return whether the ring has been processed - */ - public boolean isProcessed() { - return isProcessed; - } - - /** - * @param isProcessed whether the ring has been processed - */ - public void setProcessed(boolean isProcessed) { - this.isProcessed = isProcessed; - } - - /** - * Compares EdgeRings based on their envelope, - * using the standard lexicographic ordering. - * This ordering is sufficient to make edge ring sorting deterministic. - * - * @author mbdavis - * - */ - static class EnvelopeComparator implements Comparator { - public int compare(Object obj0, Object obj1) { - EdgeRing r0 = (EdgeRing) obj0; - EdgeRing r1 = (EdgeRing) obj1; - return r0.getRing().getEnvelope().compareTo(r1.getRing().getEnvelope()); - } - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java b/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java deleted file mode 100644 index 3aeb13c69e..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java +++ /dev/null @@ -1,114 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.polygonize; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.planargraph.DirectedEdge; -import com.vividsolutions.jts.planargraph.Node; - -/** - * A {@link DirectedEdge} of a {@link PolygonizeGraph}, which represents - * an edge of a polygon formed by the graph. - * May be logically deleted from the graph by setting the marked flag. - * - * @version 1.7 - */ -class PolygonizeDirectedEdge - extends DirectedEdge -{ - - private EdgeRing edgeRing = null; - private PolygonizeDirectedEdge next = null; - private long label = -1; - - /** - * Constructs a directed edge connecting the from node to the - * to node. - * - * @param directionPt - * specifies this DirectedEdge's direction (given by an imaginary - * line from the from node to directionPt) - * @param edgeDirection - * whether this DirectedEdge's direction is the same as or - * opposite to that of the parent Edge (if any) - */ - public PolygonizeDirectedEdge(Node from, Node to, Coordinate directionPt, - boolean edgeDirection) - { - super(from, to, directionPt, edgeDirection); - } - - /** - * Returns the identifier attached to this directed edge. - */ - public long getLabel() { return label; } - /** - * Attaches an identifier to this directed edge. - */ - public void setLabel(long label) { this.label = label; } - /** - * Returns the next directed edge in the EdgeRing that this directed edge is a member - * of. - */ - public PolygonizeDirectedEdge getNext() { return next; } - /** - * Sets the next directed edge in the EdgeRing that this directed edge is a member - * of. - */ - public void setNext(PolygonizeDirectedEdge next) { this.next = next; } - /** - * Returns the ring of directed edges that this directed edge is - * a member of, or null if the ring has not been set. - * @see #setRing(EdgeRing) - */ - public boolean isInRing() { return edgeRing != null; } - /** - * Sets the ring of directed edges that this directed edge is - * a member of. - */ - public void setRing(EdgeRing edgeRing) - { - this.edgeRing = edgeRing; - } - /** - * Gets the {@link EdgeRing} this edge is a member of. - * - * @return an edge ring - */ - public EdgeRing getRing() - { - return this.edgeRing; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java b/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java deleted file mode 100644 index 6b8d58f759..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java +++ /dev/null @@ -1,56 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - - -package com.vividsolutions.jts.operation.polygonize; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.planargraph.*; - -/** - * An edge of a polygonization graph. - * - * @version 1.7 - */ -class PolygonizeEdge - extends Edge -{ - private LineString line; - - public PolygonizeEdge(LineString line) - { - this.line = line; - } - public LineString getLine() { return line; } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java b/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java deleted file mode 100644 index 07dcaed180..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java +++ /dev/null @@ -1,444 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - - -package com.vividsolutions.jts.operation.polygonize; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Assert; -import com.vividsolutions.jts.planargraph.*; - -/** - * Represents a planar graph of edges that can be used to compute a - * polygonization, and implements the algorithms to compute the - * {@link EdgeRings} formed by the graph. - *

                      - * The marked flag on {@link DirectedEdge}s is used to indicate that a directed edge - * has be logically deleted from the graph. - * - * @version 1.7 - */ -class PolygonizeGraph - extends PlanarGraph -{ - - private static int getDegreeNonDeleted(Node node) - { - List edges = node.getOutEdges().getEdges(); - int degree = 0; - for (Iterator i = edges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - if (! de.isMarked()) degree++; - } - return degree; - } - - private static int getDegree(Node node, long label) - { - List edges = node.getOutEdges().getEdges(); - int degree = 0; - for (Iterator i = edges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - if (de.getLabel() == label) degree++; - } - return degree; - } - - /** - * Deletes all edges at a node - */ - public static void deleteAllEdges(Node node) - { - List edges = node.getOutEdges().getEdges(); - for (Iterator i = edges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - de.setMarked(true); - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) de.getSym(); - if (sym != null) - sym.setMarked(true); - } - } - - private GeometryFactory factory; - - //private List labelledRings; - - /** - * Create a new polygonization graph. - */ - public PolygonizeGraph(GeometryFactory factory) - { - this.factory = factory; - } - - /** - * Add a {@link LineString} forming an edge of the polygon graph. - * @param line the line to add - */ - public void addEdge(LineString line) - { - if (line.isEmpty()) { return; } - Coordinate[] linePts = CoordinateArrays.removeRepeatedPoints(line.getCoordinates()); - - if (linePts.length < 2) { return; } - - Coordinate startPt = linePts[0]; - Coordinate endPt = linePts[linePts.length - 1]; - - Node nStart = getNode(startPt); - Node nEnd = getNode(endPt); - - DirectedEdge de0 = new PolygonizeDirectedEdge(nStart, nEnd, linePts[1], true); - DirectedEdge de1 = new PolygonizeDirectedEdge(nEnd, nStart, linePts[linePts.length - 2], false); - Edge edge = new PolygonizeEdge(line); - edge.setDirectedEdges(de0, de1); - add(edge); - } - - private Node getNode(Coordinate pt) - { - Node node = findNode(pt); - if (node == null) { - node = new Node(pt); - // ensure node is only added once to graph - add(node); - } - return node; - } - - private void computeNextCWEdges() - { - // set the next pointers for the edges around each node - for (Iterator iNode = nodeIterator(); iNode.hasNext(); ) { - Node node = (Node) iNode.next(); - computeNextCWEdges(node); - } - } - - /** - * Convert the maximal edge rings found by the initial graph traversal - * into the minimal edge rings required by JTS polygon topology rules. - * - * @param ringEdges the list of start edges for the edgeRings to convert. - */ - private void convertMaximalToMinimalEdgeRings(List ringEdges) - { - for (Iterator i = ringEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - long label = de.getLabel(); - List intNodes = findIntersectionNodes(de, label); - - if (intNodes == null) continue; - // flip the next pointers on the intersection nodes to create minimal edge rings - for (Iterator iNode = intNodes.iterator(); iNode.hasNext(); ) { - Node node = (Node) iNode.next(); - computeNextCCWEdges(node, label); - } - } - } - - /** - * Finds all nodes in a maximal edgering which are self-intersection nodes - * @param startDE - * @param label - * @return the list of intersection nodes found, - * or null if no intersection nodes were found - */ - private static List findIntersectionNodes(PolygonizeDirectedEdge startDE, long label) - { - PolygonizeDirectedEdge de = startDE; - List intNodes = null; - do { - Node node = de.getFromNode(); - if (getDegree(node, label) > 1) { - if (intNodes == null) - intNodes = new ArrayList(); - intNodes.add(node); - } - - de = de.getNext(); - Assert.isTrue(de != null, "found null DE in ring"); - Assert.isTrue(de == startDE || ! de.isInRing(), "found DE already in ring"); - } while (de != startDE); - - return intNodes; - } - - /** - * Computes the minimal EdgeRings formed by the edges in this graph. - * @return a list of the {@link EdgeRing}s found by the polygonization process. - */ - public List getEdgeRings() - { - // maybe could optimize this, since most of these pointers should be set correctly already - // by deleteCutEdges() - computeNextCWEdges(); - // clear labels of all edges in graph - label(dirEdges, -1); - List maximalRings = findLabeledEdgeRings(dirEdges); - convertMaximalToMinimalEdgeRings(maximalRings); - - // find all edgerings (which will now be minimal ones, as required) - List edgeRingList = new ArrayList(); - for (Iterator i = dirEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - if (de.isMarked()) continue; - if (de.isInRing()) continue; - - EdgeRing er = findEdgeRing(de); - edgeRingList.add(er); - } - return edgeRingList; - } - - /** - * Finds and labels all edgerings in the graph. - * The edge rings are labeling with unique integers. - * The labeling allows detecting cut edges. - * - * @param dirEdges a List of the DirectedEdges in the graph - * @return a List of DirectedEdges, one for each edge ring found - */ - private static List findLabeledEdgeRings(Collection dirEdges) - { - List edgeRingStarts = new ArrayList(); - // label the edge rings formed - long currLabel = 1; - for (Iterator i = dirEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - if (de.isMarked()) continue; - if (de.getLabel() >= 0) continue; - - edgeRingStarts.add(de); - List edges = EdgeRing.findDirEdgesInRing(de); - - label(edges, currLabel); - currLabel++; - } - return edgeRingStarts; - } - - /** - * Finds and removes all cut edges from the graph. - * @return a list of the {@link LineString}s forming the removed cut edges - */ - public List deleteCutEdges() - { - computeNextCWEdges(); - // label the current set of edgerings - findLabeledEdgeRings(dirEdges); - - /** - * Cut Edges are edges where both dirEdges have the same label. - * Delete them, and record them - */ - List cutLines = new ArrayList(); - for (Iterator i = dirEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - if (de.isMarked()) continue; - - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) de.getSym(); - - if (de.getLabel() == sym.getLabel()) { - de.setMarked(true); - sym.setMarked(true); - - // save the line as a cut edge - PolygonizeEdge e = (PolygonizeEdge) de.getEdge(); - cutLines.add(e.getLine()); - } - } - return cutLines; - } - - private static void label(Collection dirEdges, long label) - { - for (Iterator i = dirEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - de.setLabel(label); - } - } - private static void computeNextCWEdges(Node node) - { - DirectedEdgeStar deStar = node.getOutEdges(); - PolygonizeDirectedEdge startDE = null; - PolygonizeDirectedEdge prevDE = null; - - // the edges are stored in CCW order around the star - for (Iterator i = deStar.getEdges().iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge outDE = (PolygonizeDirectedEdge) i.next(); - if (outDE.isMarked()) continue; - - if (startDE == null) - startDE = outDE; - if (prevDE != null) { - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) prevDE.getSym(); - sym.setNext(outDE); - } - prevDE = outDE; - } - if (prevDE != null) { - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) prevDE.getSym(); - sym.setNext(startDE); - } - } - /** - * Computes the next edge pointers going CCW around the given node, for the - * given edgering label. - * This algorithm has the effect of converting maximal edgerings into minimal edgerings - */ - private static void computeNextCCWEdges(Node node, long label) - { - DirectedEdgeStar deStar = node.getOutEdges(); - //PolyDirectedEdge lastInDE = null; - PolygonizeDirectedEdge firstOutDE = null; - PolygonizeDirectedEdge prevInDE = null; - - // the edges are stored in CCW order around the star - List edges = deStar.getEdges(); - //for (Iterator i = deStar.getEdges().iterator(); i.hasNext(); ) { - for (int i = edges.size() - 1; i >= 0; i--) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) edges.get(i); - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) de.getSym(); - - PolygonizeDirectedEdge outDE = null; - if ( de.getLabel() == label) outDE = de; - PolygonizeDirectedEdge inDE = null; - if ( sym.getLabel() == label) inDE = sym; - - if (outDE == null && inDE == null) continue; // this edge is not in edgering - - if (inDE != null) { - prevInDE = inDE; - } - - if (outDE != null) { - if (prevInDE != null) { - prevInDE.setNext(outDE); - prevInDE = null; - } - if (firstOutDE == null) - firstOutDE = outDE; - } - } - if (prevInDE != null) { - Assert.isTrue(firstOutDE != null); - prevInDE.setNext(firstOutDE); - } - } - - private EdgeRing findEdgeRing(PolygonizeDirectedEdge startDE) - { - EdgeRing er = new EdgeRing(factory); - er.build(startDE); - return er; - } - - /** - * Marks all edges from the graph which are "dangles". - * Dangles are which are incident on a node with degree 1. - * This process is recursive, since removing a dangling edge - * may result in another edge becoming a dangle. - * In order to handle large recursion depths efficiently, - * an explicit recursion stack is used - * - * @return a List containing the {@link LineString}s that formed dangles - */ - public Collection deleteDangles() - { - List nodesToRemove = findNodesOfDegree(1); - Set dangleLines = new HashSet(); - - Stack nodeStack = new Stack(); - for (Iterator i = nodesToRemove.iterator(); i.hasNext(); ) { - nodeStack.push(i.next()); - } - - while (! nodeStack.isEmpty()) { - Node node = (Node) nodeStack.pop(); - - deleteAllEdges(node); - List nodeOutEdges = node.getOutEdges().getEdges(); - for (Iterator i = nodeOutEdges.iterator(); i.hasNext(); ) { - PolygonizeDirectedEdge de = (PolygonizeDirectedEdge) i.next(); - // delete this edge and its sym - de.setMarked(true); - PolygonizeDirectedEdge sym = (PolygonizeDirectedEdge) de.getSym(); - if (sym != null) - sym.setMarked(true); - - // save the line as a dangle - PolygonizeEdge e = (PolygonizeEdge) de.getEdge(); - dangleLines.add(e.getLine()); - - Node toNode = de.getToNode(); - // add the toNode to the list to be processed, if it is now a dangle - if (getDegreeNonDeleted(toNode) == 1) - nodeStack.push(toNode); - } - } - return dangleLines; - } - - /** - * Traverses the polygonized edge rings in the graph - * and computes the depth parity (odd or even) - * relative to the exterior of the graph. - * If the client has requested that the output - * be polygonally valid, only odd polygons will be constructed. - * - */ - public void computeDepthParity() - { - while (true) { - PolygonizeDirectedEdge de = null; //findLowestDirEdge(); - if (de == null) - return; - computeDepthParity(de); - } - } - - /** - * Traverses all connected edges, computing the depth parity - * of the associated polygons. - * - * @param de - */ - private void computeDepthParity(PolygonizeDirectedEdge de) - { - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/polygonize/Polygonizer.java b/src/main/java/com/vividsolutions/jts/operation/polygonize/Polygonizer.java deleted file mode 100644 index 68e6228188..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/polygonize/Polygonizer.java +++ /dev/null @@ -1,373 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.polygonize; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryComponentFilter; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Polygon; - -/** - * Polygonizes a set of {@link Geometry}s which contain linework that - * represents the edges of a planar graph. - * All types of Geometry are accepted as input; - * the constituent linework is extracted as the edges to be polygonized. - * The processed edges must be correctly noded; that is, they must only meet - * at their endpoints. Polygonization will accept incorrectly noded input - * but will not form polygons from non-noded edges, - * and reports them as errors. - *

                      - * The Polygonizer reports the follow kinds of errors: - *

                        - *
                      • Dangles - edges which have one or both ends which are not incident on another edge endpoint - *
                      • Cut Edges - edges which are connected at both ends but which do not form part of polygon - *
                      • Invalid Ring Lines - edges which form rings which are invalid - * (e.g. the component lines contain a self-intersection) - *
                      - * Polygonization supports extracting only polygons which form a valid polygonal geometry. - * The set of extracted polygons is guaranteed to be edge-disjoint. - * This is useful for situations where it is known that the input lines form a - * valid polygonal geometry. - * - * @version 1.7 - */ -public class Polygonizer -{ - /** - * Adds every linear element in a {@link Geometry} into the polygonizer graph. - */ - private class LineStringAdder - implements GeometryComponentFilter - { - public void filter(Geometry g) { - if (g instanceof LineString) - add((LineString) g); - } - } - - // default factory - private LineStringAdder lineStringAdder = new LineStringAdder(); - - protected PolygonizeGraph graph; - // initialize with empty collections, in case nothing is computed - protected Collection dangles = new ArrayList(); - protected List cutEdges = new ArrayList(); - protected List invalidRingLines = new ArrayList(); - - protected List holeList = null; - protected List shellList = null; - protected List polyList = null; - - private boolean isCheckingRingsValid = true; - private boolean extractOnlyPolygonal; - - private GeometryFactory geomFactory = null; - - /** - * Creates a polygonizer with the same {@link GeometryFactory} - * as the input {@link Geometry}s. - * The output mask is {@link #ALL_POLYS}. - */ - public Polygonizer() - { - this(false); - } - - /** - * Creates a polygonizer and allow specifyng if only polygons which form a valid polygonal geometry are to be extracted. - * - * @param extractOnlyPolygonal true if only polygons which form a valid polygonal geometry are to be extracted - */ - public Polygonizer(boolean extractOnlyPolygonal) - { - this.extractOnlyPolygonal = extractOnlyPolygonal; - } - - /** - * Adds a collection of geometries to the edges to be polygonized. - * May be called multiple times. - * Any dimension of Geometry may be added; - * the constituent linework will be extracted and used. - * - * @param geomList a list of {@link Geometry}s with linework to be polygonized - */ - public void add(Collection geomList) - { - for (Iterator i = geomList.iterator(); i.hasNext(); ) { - Geometry geometry = (Geometry) i.next(); - add(geometry); - } - } - - /** - * Add a {@link Geometry} to the edges to be polygonized. - * May be called multiple times. - * Any dimension of Geometry may be added; - * the constituent linework will be extracted and used - * - * @param g a {@link Geometry} with linework to be polygonized - */ - public void add(Geometry g) - { - g.apply(lineStringAdder); - } - - /** - * Adds a linestring to the graph of polygon edges. - * - * @param line the {@link LineString} to add - */ - private void add(LineString line) - { - // record the geometry factory for later use - geomFactory = line.getFactory(); - // create a new graph using the factory from the input Geometry - if (graph == null) - graph = new PolygonizeGraph(geomFactory); - graph.addEdge(line); - } - - /** - * Allows disabling the valid ring checking, - * to optimize situations where invalid rings are not expected. - *

                      - * The default is truecontains spatial predicate - * for cases where the first {@link Geometry} is a rectangle. - * This class works for all input geometries, including - * {@link GeometryCollection}s. - *

                      - * As a further optimization, - * this class can be used to test - * many geometries against a single - * rectangle in a slightly more efficient way. - * - * @version 1.7 - */ -public class RectangleContains { - - /** - * Tests whether a rectangle contains a given geometry. - * - * @param rectangle a rectangular Polygon - * @param b a Geometry of any type - * @return true if the geometries intersect - */ - public static boolean contains(Polygon rectangle, Geometry b) - { - RectangleContains rc = new RectangleContains(rectangle); - return rc.contains(b); - } - - private Envelope rectEnv; - - /** - * Create a new contains computer for two geometries. - * - * @param rectangle a rectangular geometry - */ - public RectangleContains(Polygon rectangle) { - rectEnv = rectangle.getEnvelopeInternal(); - } - - public boolean contains(Geometry geom) - { - // the test geometry must be wholly contained in the rectangle envelope - if (! rectEnv.contains(geom.getEnvelopeInternal())) - return false; - - /** - * Check that geom is not contained entirely in the rectangle boundary. - * According to the somewhat odd spec of the SFS, if this - * is the case the geometry is NOT contained. - */ - if (isContainedInBoundary(geom)) - return false; - return true; - } - - private boolean isContainedInBoundary(Geometry geom) - { - // polygons can never be wholely contained in the boundary - if (geom instanceof Polygon) return false; - if (geom instanceof Point) return isPointContainedInBoundary((Point) geom); - if (geom instanceof LineString) return isLineStringContainedInBoundary((LineString) geom); - - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry comp = geom.getGeometryN(i); - if (! isContainedInBoundary(comp)) - return false; - } - return true; - } - - private boolean isPointContainedInBoundary(Point point) - { - return isPointContainedInBoundary(point.getCoordinate()); - } - - /** - * Tests if a point is contained in the boundary of the target rectangle. - * - * @param pt the point to test - * @return true if the point is contained in the boundary - */ - private boolean isPointContainedInBoundary(Coordinate pt) - { - /** - * contains = false iff the point is properly contained in the rectangle. - * - * This code assumes that the point lies in the rectangle envelope - */ - return pt.x == rectEnv.getMinX() - || pt.x == rectEnv.getMaxX() - || pt.y == rectEnv.getMinY() - || pt.y == rectEnv.getMaxY(); - } - - /** - * Tests if a linestring is completely contained in the boundary of the target rectangle. - * @param line the linestring to test - * @return true if the linestring is contained in the boundary - */ - private boolean isLineStringContainedInBoundary(LineString line) - { - CoordinateSequence seq = line.getCoordinateSequence(); - Coordinate p0 = new Coordinate(); - Coordinate p1 = new Coordinate(); - for (int i = 0; i < seq.size() - 1; i++) { - seq.getCoordinate(i, p0); - seq.getCoordinate(i + 1, p1); - - if (! isLineSegmentContainedInBoundary(p0, p1)) - return false; - } - return true; - } - - /** - * Tests if a line segment is contained in the boundary of the target rectangle. - * @param p0 an endpoint of the segment - * @param p1 an endpoint of the segment - * @return true if the line segment is contained in the boundary - */ - private boolean isLineSegmentContainedInBoundary(Coordinate p0, Coordinate p1) - { - if (p0.equals(p1)) - return isPointContainedInBoundary(p0); - - // we already know that the segment is contained in the rectangle envelope - if (p0.x == p1.x) { - if (p0.x == rectEnv.getMinX() || - p0.x == rectEnv.getMaxX() ) - return true; - } - else if (p0.y == p1.y) { - if (p0.y == rectEnv.getMinY() || - p0.y == rectEnv.getMaxY() ) - return true; - } - /** - * Either - * both x and y values are different - * or - * one of x and y are the same, but the other ordinate is not the same as a boundary ordinate - * - * In either case, the segment is not wholely in the boundary - */ - return false; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java b/src/main/java/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java deleted file mode 100644 index 52f77fc3f3..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java +++ /dev/null @@ -1,353 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.predicate; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.algorithm.locate.SimplePointInAreaLocator; -import com.vividsolutions.jts.geom.util.*; - -/** - * Implementation of the intersects spatial predicate - * optimized for the case where one {@link Geometry} is a rectangle. - * This class works for all - * input geometries, including {@link GeometryCollection}s. - *

                      - * As a further optimization, - * this class can be used in batch style - * to test many geometries - * against a single rectangle. - * - * @version 1.7 - */ -public class RectangleIntersects -{ - /** - * Tests whether a rectangle intersects a given geometry. - * - * @param rectangle - * a rectangular Polygon - * @param b - * a Geometry of any type - * @return true if the geometries intersect - */ - public static boolean intersects(Polygon rectangle, Geometry b) - { - RectangleIntersects rp = new RectangleIntersects(rectangle); - return rp.intersects(b); - } - - private Polygon rectangle; - - private Envelope rectEnv; - - /** - * Create a new intersects computer for a rectangle. - * - * @param rectangle - * a rectangular Polygon - */ - public RectangleIntersects(Polygon rectangle) - { - this.rectangle = rectangle; - rectEnv = rectangle.getEnvelopeInternal(); - } - - /** - * Tests whether the given Geometry intersects - * the query rectangle. - * - * @param geom the Geometry to test (may be of any type) - * @return true if the geometry intersects the query rectangle - */ - public boolean intersects(Geometry geom) - { - if (!rectEnv.intersects(geom.getEnvelopeInternal())) - return false; - - /** - * Test if rectangle envelope intersects any component envelope. - * This handles Point components as well - */ - EnvelopeIntersectsVisitor visitor = new EnvelopeIntersectsVisitor(rectEnv); - visitor.applyTo(geom); - if (visitor.intersects()) - return true; - - /** - * Test if any rectangle vertex is contained in the target geometry - */ - GeometryContainsPointVisitor ecpVisitor = new GeometryContainsPointVisitor(rectangle); - ecpVisitor.applyTo(geom); - if (ecpVisitor.containsPoint()) - return true; - - /** - * Test if any target geometry line segment intersects the rectangle - */ - RectangleIntersectsSegmentVisitor riVisitor = new RectangleIntersectsSegmentVisitor(rectangle); - riVisitor.applyTo(geom); - if (riVisitor.intersects()) - return true; - - return false; - } -} - -/** - * Tests whether it can be concluded that a rectangle intersects a geometry, - * based on the relationship of the envelope(s) of the geometry. - * - * @author Martin Davis - * @version 1.7 - */ -class EnvelopeIntersectsVisitor extends ShortCircuitedGeometryVisitor -{ - private Envelope rectEnv; - - private boolean intersects = false; - - public EnvelopeIntersectsVisitor(Envelope rectEnv) - { - this.rectEnv = rectEnv; - } - - /** - * Reports whether it can be concluded that an intersection occurs, - * or whether further testing is required. - * - * @return true if an intersection must occur - * or false if no conclusion about intersection can be made - */ - public boolean intersects() - { - return intersects; - } - - protected void visit(Geometry element) - { - Envelope elementEnv = element.getEnvelopeInternal(); - - // disjoint => no intersection - if (!rectEnv.intersects(elementEnv)) { - return; - } - // rectangle contains target env => must intersect - if (rectEnv.contains(elementEnv)) { - intersects = true; - return; - } - /** - * Since the envelopes intersect and the test element is connected, if the - * test envelope is completely bisected by an edge of the rectangle the - * element and the rectangle must touch (This is basically an application of - * the Jordan Curve Theorem). The alternative situation is that the test - * envelope is "on a corner" of the rectangle envelope, i.e. is not - * completely bisected. In this case it is not possible to make a conclusion - * about the presence of an intersection. - */ - if (elementEnv.getMinX() >= rectEnv.getMinX() - && elementEnv.getMaxX() <= rectEnv.getMaxX()) { - intersects = true; - return; - } - if (elementEnv.getMinY() >= rectEnv.getMinY() - && elementEnv.getMaxY() <= rectEnv.getMaxY()) { - intersects = true; - return; - } - } - - protected boolean isDone() - { - return intersects == true; - } -} - -/** - * A visitor which tests whether it can be - * concluded that a geometry contains a vertex of - * a query geometry. - * - * @author Martin Davis - * @version 1.7 - */ -class GeometryContainsPointVisitor extends ShortCircuitedGeometryVisitor -{ - private CoordinateSequence rectSeq; - - private Envelope rectEnv; - - private boolean containsPoint = false; - - public GeometryContainsPointVisitor(Polygon rectangle) - { - this.rectSeq = rectangle.getExteriorRing().getCoordinateSequence(); - rectEnv = rectangle.getEnvelopeInternal(); - } - - /** - * Reports whether it can be concluded that a corner point of the rectangle is - * contained in the geometry, or whether further testing is required. - * - * @return true if a corner point is contained - * or false if no conclusion about intersection can be made - */ - public boolean containsPoint() - { - return containsPoint; - } - - protected void visit(Geometry geom) - { - // if test geometry is not polygonal this check is not needed - if (!(geom instanceof Polygon)) - return; - - // skip if envelopes do not intersect - Envelope elementEnv = geom.getEnvelopeInternal(); - if (!rectEnv.intersects(elementEnv)) - return; - - // test each corner of rectangle for inclusion - Coordinate rectPt = new Coordinate(); - for (int i = 0; i < 4; i++) { - rectSeq.getCoordinate(i, rectPt); - if (!elementEnv.contains(rectPt)) - continue; - // check rect point in poly (rect is known not to touch polygon at this - // point) - if (SimplePointInAreaLocator.containsPointInPolygon(rectPt, - (Polygon) geom)) { - containsPoint = true; - return; - } - } - } - - protected boolean isDone() - { - return containsPoint == true; - } -} - - -/** - * A visitor to test for intersection between the query - * rectangle and the line segments of the geometry. - * - * @author Martin Davis - * - */ -class RectangleIntersectsSegmentVisitor extends ShortCircuitedGeometryVisitor -{ - private Envelope rectEnv; - private RectangleLineIntersector rectIntersector; - - private boolean hasIntersection = false; - private Coordinate p0 = new Coordinate(); - private Coordinate p1 = new Coordinate(); - - /** - * Creates a visitor for checking rectangle intersection - * with segments - * - * @param rectangle the query rectangle - */ - public RectangleIntersectsSegmentVisitor(Polygon rectangle) - { - rectEnv = rectangle.getEnvelopeInternal(); - rectIntersector = new RectangleLineIntersector(rectEnv); - } - - /** - * Reports whether any segment intersection exists. - * - * @return true if a segment intersection exists - * or false if no segment intersection exists - */ - public boolean intersects() - { - return hasIntersection; - } - - protected void visit(Geometry geom) - { - /** - * It may be the case that the rectangle and the - * envelope of the geometry component are disjoint, - * so it is worth checking this simple condition. - */ - Envelope elementEnv = geom.getEnvelopeInternal(); - if (!rectEnv.intersects(elementEnv)) - return; - - // check segment intersections - // get all lines from geometry component - // (there may be more than one if it's a multi-ring polygon) - List lines = LinearComponentExtracter.getLines(geom); - checkIntersectionWithLineStrings(lines); - } - - private void checkIntersectionWithLineStrings(List lines) - { - for (Iterator i = lines.iterator(); i.hasNext(); ) { - LineString testLine = (LineString) i.next(); - checkIntersectionWithSegments(testLine); - if (hasIntersection) - return; - } - } - - private void checkIntersectionWithSegments(LineString testLine) - { - CoordinateSequence seq1 = testLine.getCoordinateSequence(); - for (int j = 1; j < seq1.size(); j++) { - seq1.getCoordinate(j - 1, p0); - seq1.getCoordinate(j, p1); - - if (rectIntersector.intersects(p0, p1)) { - hasIntersection = true; - return; - } - } - } - - protected boolean isDone() - { - return hasIntersection == true; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java b/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java deleted file mode 100644 index 62cb8e36e7..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java +++ /dev/null @@ -1,165 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -/** - * An EdgeEndBuilder creates EdgeEnds for all the "split edges" - * created by the - * intersections determined for an Edge. - * - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.*; - -/** - * Computes the {@link EdgeEnd}s which arise from a noded {@link Edge}. - * - * @version 1.7 - */ -public class EdgeEndBuilder { - - public EdgeEndBuilder() { - } - - public List computeEdgeEnds(Iterator edges) - { - List l = new ArrayList(); - for (Iterator i = edges; i.hasNext(); ) { - Edge e = (Edge) i.next(); - computeEdgeEnds(e, l); - } - return l; - } - - /** - * Creates stub edges for all the intersections in this - * Edge (if any) and inserts them into the graph. - */ - public void computeEdgeEnds(Edge edge, List l) - { - EdgeIntersectionList eiList = edge.getEdgeIntersectionList(); -//Debug.print(eiList); - // ensure that the list has entries for the first and last point of the edge - eiList.addEndpoints(); - - Iterator it = eiList.iterator(); - EdgeIntersection eiPrev = null; - EdgeIntersection eiCurr = null; - // no intersections, so there is nothing to do - if (! it.hasNext()) return; - EdgeIntersection eiNext = (EdgeIntersection) it.next(); - do { - eiPrev = eiCurr; - eiCurr = eiNext; - eiNext = null; - if (it.hasNext()) eiNext = (EdgeIntersection) it.next(); - - if (eiCurr != null) { - createEdgeEndForPrev(edge, l, eiCurr, eiPrev); - createEdgeEndForNext(edge, l, eiCurr, eiNext); - } - - } while (eiCurr != null); - - } - - /** - * Create a EdgeStub for the edge before the intersection eiCurr. - * The previous intersection is provided - * in case it is the endpoint for the stub edge. - * Otherwise, the previous point from the parent edge will be the endpoint. - *
                      - * eiCurr will always be an EdgeIntersection, but eiPrev may be null. - */ - void createEdgeEndForPrev( - Edge edge, - List l, - EdgeIntersection eiCurr, - EdgeIntersection eiPrev) - { - - int iPrev = eiCurr.segmentIndex; - if (eiCurr.dist == 0.0) { - // if at the start of the edge there is no previous edge - if (iPrev == 0) return; - iPrev--; - } - Coordinate pPrev = edge.getCoordinate(iPrev); - // if prev intersection is past the previous vertex, use it instead - if (eiPrev != null && eiPrev.segmentIndex >= iPrev) - pPrev = eiPrev.coord; - - Label label = new Label(edge.getLabel()); - // since edgeStub is oriented opposite to it's parent edge, have to flip sides for edge label - label.flip(); - EdgeEnd e = new EdgeEnd(edge, eiCurr.coord, pPrev, label); -//e.print(System.out); System.out.println(); - l.add(e); - } - /** - * Create a StubEdge for the edge after the intersection eiCurr. - * The next intersection is provided - * in case it is the endpoint for the stub edge. - * Otherwise, the next point from the parent edge will be the endpoint. - *
                      - * eiCurr will always be an EdgeIntersection, but eiNext may be null. - */ - void createEdgeEndForNext( - Edge edge, - List l, - EdgeIntersection eiCurr, - EdgeIntersection eiNext) - { - - int iNext = eiCurr.segmentIndex + 1; - // if there is no next edge there is nothing to do - if (iNext >= edge.getNumPoints() && eiNext == null) return; - - Coordinate pNext = edge.getCoordinate(iNext); - - // if the next intersection is in the same segment as the current, use it as the endpoint - if (eiNext != null && eiNext.segmentIndex == eiCurr.segmentIndex) - pNext = eiNext.coord; - - EdgeEnd e = new EdgeEnd(edge, eiCurr.coord, pNext, new Label(edge.getLabel())); -//Debug.println(e); - l.add(e); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java b/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java deleted file mode 100644 index 2737ff7c74..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java +++ /dev/null @@ -1,206 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.Assert; -import com.vividsolutions.jts.algorithm.BoundaryNodeRule; - -/** - * A collection of {@link EdgeEnd}s which obey the following invariant: - * They originate at the same node and have the same direction. - * - * @version 1.7 - */ -public class EdgeEndBundle - extends EdgeEnd -{ -// private BoundaryNodeRule boundaryNodeRule; - private List edgeEnds = new ArrayList(); - - public EdgeEndBundle(BoundaryNodeRule boundaryNodeRule, EdgeEnd e) - { - super(e.getEdge(), e.getCoordinate(), e.getDirectedCoordinate(), new Label(e.getLabel())); - insert(e); - /* - if (boundaryNodeRule != null) - this.boundaryNodeRule = boundaryNodeRule; - else - boundaryNodeRule = BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE; - */ - } - - public EdgeEndBundle(EdgeEnd e) - { - this(null, e); - } - - public Label getLabel() { return label; } - public Iterator iterator() { return edgeEnds.iterator(); } - public List getEdgeEnds() { return edgeEnds; } - - public void insert(EdgeEnd e) - { - // Assert: start point is the same - // Assert: direction is the same - edgeEnds.add(e); - } - /** - * This computes the overall edge label for the set of - * edges in this EdgeStubBundle. It essentially merges - * the ON and side labels for each edge. These labels must be compatible - */ - public void computeLabel(BoundaryNodeRule boundaryNodeRule) - { - // create the label. If any of the edges belong to areas, - // the label must be an area label - boolean isArea = false; - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - if (e.getLabel().isArea()) isArea = true; - } - if (isArea) - label = new Label(Location.NONE, Location.NONE, Location.NONE); - else - label = new Label(Location.NONE); - - // compute the On label, and the side labels if present - for (int i = 0; i < 2; i++) { - computeLabelOn(i, boundaryNodeRule); - if (isArea) - computeLabelSides(i); - } - } - - /** - * Compute the overall ON location for the list of EdgeStubs. - * (This is essentially equivalent to computing the self-overlay of a single Geometry) - * edgeStubs can be either on the boundary (eg Polygon edge) - * OR in the interior (e.g. segment of a LineString) - * of their parent Geometry. - * In addition, GeometryCollections use a {@link BoundaryNodeRule} to determine - * whether a segment is on the boundary or not. - * Finally, in GeometryCollections it can occur that an edge is both - * on the boundary and in the interior (e.g. a LineString segment lying on - * top of a Polygon edge.) In this case the Boundary is given precendence. - *
                      - * These observations result in the following rules for computing the ON location: - *

                        - *
                      • if there are an odd number of Bdy edges, the attribute is Bdy - *
                      • if there are an even number >= 2 of Bdy edges, the attribute is Int - *
                      • if there are any Int edges, the attribute is Int - *
                      • otherwise, the attribute is NULL. - *
                      - */ - private void computeLabelOn(int geomIndex, BoundaryNodeRule boundaryNodeRule) - { - // compute the ON location value - int boundaryCount = 0; - boolean foundInterior = false; - - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - int loc = e.getLabel().getLocation(geomIndex); - if (loc == Location.BOUNDARY) boundaryCount++; - if (loc == Location.INTERIOR) foundInterior = true; - } - int loc = Location.NONE; - if (foundInterior) loc = Location.INTERIOR; - if (boundaryCount > 0) { - loc = GeometryGraph.determineBoundary(boundaryNodeRule, boundaryCount); - } - label.setLocation(geomIndex, loc); - - } - /** - * Compute the labelling for each side - */ - private void computeLabelSides(int geomIndex) - { - computeLabelSide(geomIndex, Position.LEFT); - computeLabelSide(geomIndex, Position.RIGHT); - } - - /** - * To compute the summary label for a side, the algorithm is: - * FOR all edges - * IF any edge's location is INTERIOR for the side, side location = INTERIOR - * ELSE IF there is at least one EXTERIOR attribute, side location = EXTERIOR - * ELSE side location = NULL - *
                      - * Note that it is possible for two sides to have apparently contradictory information - * i.e. one edge side may indicate that it is in the interior of a geometry, while - * another edge side may indicate the exterior of the same geometry. This is - * not an incompatibility - GeometryCollections may contain two Polygons that touch - * along an edge. This is the reason for Interior-primacy rule above - it - * results in the summary label having the Geometry interior on both sides. - */ - private void computeLabelSide(int geomIndex, int side) - { - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd e = (EdgeEnd) it.next(); - if (e.getLabel().isArea()) { - int loc = e.getLabel().getLocation(geomIndex, side); - if (loc == Location.INTERIOR) { - label.setLocation(geomIndex, side, Location.INTERIOR); - return; - } - else if (loc == Location.EXTERIOR) - label.setLocation(geomIndex, side, Location.EXTERIOR); - } - } - } - - /** - * Update the IM with the contribution for the computed label for the EdgeStubs. - */ - void updateIM(IntersectionMatrix im) - { - Edge.updateIM(label, im); - } - public void print(PrintStream out) - { - out.println("EdgeEndBundle--> Label: " + label); - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEnd ee = (EdgeEnd) it.next(); - ee.print(out); - out.println(); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java b/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java deleted file mode 100644 index c7dbd6bf68..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java +++ /dev/null @@ -1,91 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.Assert; - -/** - * An ordered list of {@link EdgeEndBundle}s around a {@link RelateNode}. - * They are maintained in CCW order (starting with the positive x-axis) around the node - * for efficient lookup and topology building. - * - * @version 1.7 - */ -public class EdgeEndBundleStar - extends EdgeEndStar -{ - /** - * Creates a new empty EdgeEndBundleStar - */ - public EdgeEndBundleStar() { - } - - /** - * Insert a EdgeEnd in order in the list. - * If there is an existing EdgeStubBundle which is parallel, the EdgeEnd is - * added to the bundle. Otherwise, a new EdgeEndBundle is created - * to contain the EdgeEnd. - *
                      - */ - public void insert(EdgeEnd e) - { - EdgeEndBundle eb = (EdgeEndBundle) edgeMap.get(e); - if (eb == null) { - eb = new EdgeEndBundle(e); - insertEdgeEnd(e, eb); - } - else { - eb.insert(e); - } - } - - /** - * Update the IM with the contribution for the EdgeStubs around the node. - */ - void updateIM(IntersectionMatrix im) - { - for (Iterator it = iterator(); it.hasNext(); ) { - EdgeEndBundle esb = (EdgeEndBundle) it.next(); - esb.updateIM(im); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/RelateComputer.java b/src/main/java/com/vividsolutions/jts/operation/relate/RelateComputer.java deleted file mode 100644 index c6988f33e6..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/RelateComputer.java +++ /dev/null @@ -1,396 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geomgraph.index.SegmentIntersector; - -/** - * Computes the topological relationship between two Geometries. - *

                      - * RelateComputer does not need to build a complete graph structure to compute - * the IntersectionMatrix. The relationship between the geometries can - * be computed by simply examining the labelling of edges incident on each node. - *

                      - * RelateComputer does not currently support arbitrary GeometryCollections. - * This is because GeometryCollections can contain overlapping Polygons. - * In order to correct compute relate on overlapping Polygons, they - * would first need to be noded and merged (if not explicitly, at least - * implicitly). - * - * @version 1.7 - */ -public class RelateComputer -{ - private LineIntersector li = new RobustLineIntersector(); - private PointLocator ptLocator = new PointLocator(); - private GeometryGraph[] arg; // the arg(s) of the operation - private NodeMap nodes = new NodeMap(new RelateNodeFactory()); - // this intersection matrix will hold the results compute for the relate - private IntersectionMatrix im = null; - private ArrayList isolatedEdges = new ArrayList(); - - // the intersection point found (if any) - private Coordinate invalidPoint; - - public RelateComputer(GeometryGraph[] arg) { - this.arg = arg; - } - - public IntersectionMatrix computeIM() - { - IntersectionMatrix im = new IntersectionMatrix(); - // since Geometries are finite and embedded in a 2-D space, the EE element must always be 2 - im.set(Location.EXTERIOR, Location.EXTERIOR, 2); - - // if the Geometries don't overlap there is nothing to do - if (! arg[0].getGeometry().getEnvelopeInternal().intersects( - arg[1].getGeometry().getEnvelopeInternal()) ) { - computeDisjointIM(im); - return im; - } - arg[0].computeSelfNodes(li, false); - arg[1].computeSelfNodes(li, false); - - // compute intersections between edges of the two input geometries - SegmentIntersector intersector = arg[0].computeEdgeIntersections(arg[1], li, false); -//System.out.println("computeIM: # segment intersection tests: " + intersector.numTests); - computeIntersectionNodes(0); - computeIntersectionNodes(1); - /** - * Copy the labelling for the nodes in the parent Geometries. These override - * any labels determined by intersections between the geometries. - */ - copyNodesAndLabels(0); - copyNodesAndLabels(1); - - // complete the labelling for any nodes which only have a label for a single geometry -//Debug.addWatch(nodes.find(new Coordinate(110, 200))); -//Debug.printWatch(); - labelIsolatedNodes(); -//Debug.printWatch(); - - // If a proper intersection was found, we can set a lower bound on the IM. - computeProperIntersectionIM(intersector, im); - - /** - * Now process improper intersections - * (eg where one or other of the geometries has a vertex at the intersection point) - * We need to compute the edge graph at all nodes to determine the IM. - */ - - // build EdgeEnds for all intersections - EdgeEndBuilder eeBuilder = new EdgeEndBuilder(); - List ee0 = eeBuilder.computeEdgeEnds(arg[0].getEdgeIterator()); - insertEdgeEnds(ee0); - List ee1 = eeBuilder.computeEdgeEnds(arg[1].getEdgeIterator()); - insertEdgeEnds(ee1); - -//Debug.println("==== NodeList ==="); -//Debug.print(nodes); - - labelNodeEdges(); - - /** - * Compute the labeling for isolated components - *
                      - * Isolated components are components that do not touch any other components in the graph. - * They can be identified by the fact that they will - * contain labels containing ONLY a single element, the one for their parent geometry. - * We only need to check components contained in the input graphs, since - * isolated components will not have been replaced by new components formed by intersections. - */ -//debugPrintln("Graph A isolated edges - "); - labelIsolatedEdges(0, 1); -//debugPrintln("Graph B isolated edges - "); - labelIsolatedEdges(1, 0); - - // update the IM from all components - updateIM(im); - return im; - } - - private void insertEdgeEnds(List ee) - { - for (Iterator i = ee.iterator(); i.hasNext(); ) { - EdgeEnd e = (EdgeEnd) i.next(); - nodes.add(e); - } - } - - private void computeProperIntersectionIM(SegmentIntersector intersector, IntersectionMatrix im) - { - // If a proper intersection is found, we can set a lower bound on the IM. - int dimA = arg[0].getGeometry().getDimension(); - int dimB = arg[1].getGeometry().getDimension(); - boolean hasProper = intersector.hasProperIntersection(); - boolean hasProperInterior = intersector.hasProperInteriorIntersection(); - - // For Geometry's of dim 0 there can never be proper intersections. - - /** - * If edge segments of Areas properly intersect, the areas must properly overlap. - */ - if (dimA == 2 && dimB == 2) { - if (hasProper) im.setAtLeast("212101212"); - } - /** - * If an Line segment properly intersects an edge segment of an Area, - * it follows that the Interior of the Line intersects the Boundary of the Area. - * If the intersection is a proper interior intersection, then - * there is an Interior-Interior intersection too. - * Note that it does not follow that the Interior of the Line intersects the Exterior - * of the Area, since there may be another Area component which contains the rest of the Line. - */ - else if (dimA == 2 && dimB == 1) { - if (hasProper) im.setAtLeast("FFF0FFFF2"); - if (hasProperInterior) im.setAtLeast("1FFFFF1FF"); - } - else if (dimA == 1 && dimB == 2) { - if (hasProper) im.setAtLeast("F0FFFFFF2"); - if (hasProperInterior) im.setAtLeast("1F1FFFFFF"); - } - /* If edges of LineStrings properly intersect *in an interior point*, all - we can deduce is that - the interiors intersect. (We can NOT deduce that the exteriors intersect, - since some other segments in the geometries might cover the points in the - neighbourhood of the intersection.) - It is important that the point be known to be an interior point of - both Geometries, since it is possible in a self-intersecting geometry to - have a proper intersection on one segment that is also a boundary point of another segment. - */ - else if (dimA == 1 && dimB == 1) { - if (hasProperInterior) im.setAtLeast("0FFFFFFFF"); - } - } - - /** - * Copy all nodes from an arg geometry into this graph. - * The node label in the arg geometry overrides any previously computed - * label for that argIndex. - * (E.g. a node may be an intersection node with - * a computed label of BOUNDARY, - * but in the original arg Geometry it is actually - * in the interior due to the Boundary Determination Rule) - */ - private void copyNodesAndLabels(int argIndex) - { - for (Iterator i = arg[argIndex].getNodeIterator(); i.hasNext(); ) { - Node graphNode = (Node) i.next(); - Node newNode = nodes.addNode(graphNode.getCoordinate()); - newNode.setLabel(argIndex, graphNode.getLabel().getLocation(argIndex)); -//node.print(System.out); - } - } - /** - * Insert nodes for all intersections on the edges of a Geometry. - * Label the created nodes the same as the edge label if they do not already have a label. - * This allows nodes created by either self-intersections or - * mutual intersections to be labelled. - * Endpoint nodes will already be labelled from when they were inserted. - */ - private void computeIntersectionNodes(int argIndex) - { - for (Iterator i = arg[argIndex].getEdgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - int eLoc = e.getLabel().getLocation(argIndex); - for (Iterator eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) eiIt.next(); - RelateNode n = (RelateNode) nodes.addNode(ei.coord); - if (eLoc == Location.BOUNDARY) - n.setLabelBoundary(argIndex); - else { - if (n.getLabel().isNull(argIndex)) - n.setLabel(argIndex, Location.INTERIOR); - } -//Debug.println(n); - } - } - } - /** - * For all intersections on the edges of a Geometry, - * label the corresponding node IF it doesn't already have a label. - * This allows nodes created by either self-intersections or - * mutual intersections to be labelled. - * Endpoint nodes will already be labelled from when they were inserted. - */ - private void labelIntersectionNodes(int argIndex) - { - for (Iterator i = arg[argIndex].getEdgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - int eLoc = e.getLabel().getLocation(argIndex); - for (Iterator eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) eiIt.next(); - RelateNode n = (RelateNode) nodes.find(ei.coord); - if (n.getLabel().isNull(argIndex)) { - if (eLoc == Location.BOUNDARY) - n.setLabelBoundary(argIndex); - else - n.setLabel(argIndex, Location.INTERIOR); - } -//n.print(System.out); - } - } - } - /** - * If the Geometries are disjoint, we need to enter their dimension and - * boundary dimension in the Ext rows in the IM - */ - private void computeDisjointIM(IntersectionMatrix im) - { - Geometry ga = arg[0].getGeometry(); - if (! ga.isEmpty()) { - im.set(Location.INTERIOR, Location.EXTERIOR, ga.getDimension()); - im.set(Location.BOUNDARY, Location.EXTERIOR, ga.getBoundaryDimension()); - } - Geometry gb = arg[1].getGeometry(); - if (! gb.isEmpty()) { - im.set(Location.EXTERIOR, Location.INTERIOR, gb.getDimension()); - im.set(Location.EXTERIOR, Location.BOUNDARY, gb.getBoundaryDimension()); - } - } - - private void labelNodeEdges() - { - for (Iterator ni = nodes.iterator(); ni.hasNext(); ) { - RelateNode node = (RelateNode) ni.next(); - node.getEdges().computeLabelling(arg); -//Debug.print(node.getEdges()); -//node.print(System.out); - } - } - - /** - * update the IM with the sum of the IMs for each component - */ - private void updateIM(IntersectionMatrix im) - { -//Debug.println(im); - for (Iterator ei = isolatedEdges.iterator(); ei.hasNext(); ) { - Edge e = (Edge) ei.next(); - e.updateIM(im); -//Debug.println(im); - } - for (Iterator ni = nodes.iterator(); ni.hasNext(); ) { - RelateNode node = (RelateNode) ni.next(); - node.updateIM(im); -//Debug.println(im); - node.updateIMFromEdges(im); -//Debug.println(im); -//node.print(System.out); - } - } - - /** - * Processes isolated edges by computing their labelling and adding them - * to the isolated edges list. - * Isolated edges are guaranteed not to touch the boundary of the target (since if they - * did, they would have caused an intersection to be computed and hence would - * not be isolated) - */ - private void labelIsolatedEdges(int thisIndex, int targetIndex) - { - for (Iterator ei = arg[thisIndex].getEdgeIterator(); ei.hasNext(); ) { - Edge e = (Edge) ei.next(); - if (e.isIsolated()) { - labelIsolatedEdge(e, targetIndex, arg[targetIndex].getGeometry()); - isolatedEdges.add(e); - } - } - } - /** - * Label an isolated edge of a graph with its relationship to the target geometry. - * If the target has dim 2 or 1, the edge can either be in the interior or the exterior. - * If the target has dim 0, the edge must be in the exterior - */ - private void labelIsolatedEdge(Edge e, int targetIndex, Geometry target) - { - // this won't work for GeometryCollections with both dim 2 and 1 geoms - if ( target.getDimension() > 0) { - // since edge is not in boundary, may not need the full generality of PointLocator? - // Possibly should use ptInArea locator instead? We probably know here - // that the edge does not touch the bdy of the target Geometry - int loc = ptLocator.locate(e.getCoordinate(), target); - e.getLabel().setAllLocations(targetIndex, loc); - } - else { - e.getLabel().setAllLocations(targetIndex, Location.EXTERIOR); - } -//System.out.println(e.getLabel()); - } - - /** - * Isolated nodes are nodes whose labels are incomplete - * (e.g. the location for one Geometry is null). - * This is the case because nodes in one graph which don't intersect - * nodes in the other are not completely labelled by the initial process - * of adding nodes to the nodeList. - * To complete the labelling we need to check for nodes that lie in the - * interior of edges, and in the interior of areas. - */ - private void labelIsolatedNodes() - { - for (Iterator ni = nodes.iterator(); ni.hasNext(); ) { - Node n = (Node) ni.next(); - Label label = n.getLabel(); - // isolated nodes should always have at least one geometry in their label - Assert.isTrue(label.getGeometryCount() > 0, "node with empty label found"); - if (n.isIsolated()) { - if (label.isNull(0)) - labelIsolatedNode(n, 0); - else - labelIsolatedNode(n, 1); - } - } - } - - /** - * Label an isolated node with its relationship to the target geometry. - */ - private void labelIsolatedNode(Node n, int targetIndex) - { - int loc = ptLocator.locate(n.getCoordinate(), arg[targetIndex].getGeometry()); - n.getLabel().setAllLocations(targetIndex, loc); -//debugPrintln(n.getLabel()); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNode.java b/src/main/java/com/vividsolutions/jts/operation/relate/RelateNode.java deleted file mode 100644 index 1509aa1c7d..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNode.java +++ /dev/null @@ -1,81 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -/** - * A RelateNode is a Node that maintains a list of EdgeStubs - * for the edges that are incident on it. - * - * @version 1.7 - */ - -import java.io.PrintStream; -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Represents a node in the topological graph used to compute spatial relationships. - * - * @version 1.7 - */ -public class RelateNode - extends Node -{ - - public RelateNode(Coordinate coord, EdgeEndStar edges) - { - super(coord, edges); - } - - /** - * Update the IM with the contribution for this component. - * A component only contributes if it has a labelling for both parent geometries - */ - protected void computeIM(IntersectionMatrix im) - { - im.setAtLeastIfValid(label.getLocation(0), label.getLocation(1), 0); - } - /** - * Update the IM with the contribution for the EdgeEnds incident on this node. - */ - void updateIMFromEdges(IntersectionMatrix im) - { - ((EdgeEndBundleStar) edges).updateIM(im); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java b/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java deleted file mode 100644 index 8372769f9b..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java +++ /dev/null @@ -1,52 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Used by the {@link NodeMap} in a {@link RelateNodeGraph} to create {@link RelateNode}s. - * - * @version 1.7 - */ -public class RelateNodeFactory - extends NodeFactory -{ - public Node createNode(Coordinate coord) - { - return new RelateNode(coord, new EdgeEndBundleStar()); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java b/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java deleted file mode 100644 index d7e704edb9..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java +++ /dev/null @@ -1,150 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -/** - * @version 1.7 - */ -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; -import com.vividsolutions.jts.geomgraph.*; - -/** - * Implements the simple graph of Nodes and EdgeEnd which is all that is - * required to determine topological relationships between Geometries. - * Also supports building a topological graph of a single Geometry, to - * allow verification of valid topology. - *

                      - * It is not necessary to create a fully linked - * PlanarGraph to determine relationships, since it is sufficient - * to know how the Geometries interact locally around the nodes. - * In fact, this is not even feasible, since it is not possible to compute - * exact intersection points, and hence the topology around those nodes - * cannot be computed robustly. - * The only Nodes that are created are for improper intersections; - * that is, nodes which occur at existing vertices of the Geometries. - * Proper intersections (e.g. ones which occur between the interior of line segments) - * have their topology determined implicitly, without creating a Node object - * to represent them. - * - * @version 1.7 - */ -public class RelateNodeGraph { - - private NodeMap nodes = new NodeMap(new RelateNodeFactory()); - - public RelateNodeGraph() { - } - - public Iterator getNodeIterator() { return nodes.iterator(); } - - public void build(GeometryGraph geomGraph) - { - // compute nodes for intersections between previously noded edges - computeIntersectionNodes(geomGraph, 0); - /** - * Copy the labelling for the nodes in the parent Geometry. These override - * any labels determined by intersections. - */ - copyNodesAndLabels(geomGraph, 0); - - /** - * Build EdgeEnds for all intersections. - */ - EdgeEndBuilder eeBuilder = new EdgeEndBuilder(); - List eeList = eeBuilder.computeEdgeEnds(geomGraph.getEdgeIterator()); - insertEdgeEnds(eeList); - -//Debug.println("==== NodeList ==="); -//Debug.print(nodes); - } - - /** - * Insert nodes for all intersections on the edges of a Geometry. - * Label the created nodes the same as the edge label if they do not already have a label. - * This allows nodes created by either self-intersections or - * mutual intersections to be labelled. - * Endpoint nodes will already be labelled from when they were inserted. - *

                      - * Precondition: edge intersections have been computed. - */ - public void computeIntersectionNodes(GeometryGraph geomGraph, int argIndex) - { - for (Iterator edgeIt = geomGraph.getEdgeIterator(); edgeIt.hasNext(); ) { - Edge e = (Edge) edgeIt.next(); - int eLoc = e.getLabel().getLocation(argIndex); - for (Iterator eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) eiIt.next(); - RelateNode n = (RelateNode) nodes.addNode(ei.coord); - if (eLoc == Location.BOUNDARY) - n.setLabelBoundary(argIndex); - else { - if (n.getLabel().isNull(argIndex)) - n.setLabel(argIndex, Location.INTERIOR); - } -//Debug.println(n); - } - } - } - - /** - * Copy all nodes from an arg geometry into this graph. - * The node label in the arg geometry overrides any previously computed - * label for that argIndex. - * (E.g. a node may be an intersection node with - * a computed label of BOUNDARY, - * but in the original arg Geometry it is actually - * in the interior due to the Boundary Determination Rule) - */ - public void copyNodesAndLabels(GeometryGraph geomGraph, int argIndex) - { - for (Iterator nodeIt = geomGraph.getNodeIterator(); nodeIt.hasNext(); ) { - Node graphNode = (Node) nodeIt.next(); - Node newNode = nodes.addNode(graphNode.getCoordinate()); - newNode.setLabel(argIndex, graphNode.getLabel().getLocation(argIndex)); -//node.print(System.out); - } - } - - public void insertEdgeEnds(List ee) - { - for (Iterator i = ee.iterator(); i.hasNext(); ) { - EdgeEnd e = (EdgeEnd) i.next(); - nodes.add(e); - } - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/relate/RelateOp.java b/src/main/java/com/vividsolutions/jts/operation/relate/RelateOp.java deleted file mode 100644 index 10d9f0e7d1..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/relate/RelateOp.java +++ /dev/null @@ -1,141 +0,0 @@ - - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.relate; - -/** - * @version 1.7 - */ - -import com.vividsolutions.jts.algorithm.BoundaryNodeRule; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.operation.GeometryGraphOperation; -import java.util.*; - -/** - * Implements the SFS relate() generalized spatial predicate on two {@link Geometry}s. - * - * The class supports specifying a custom {@link BoundaryNodeRule} - * to be used during the relate computation. - *

                      - * If named spatial predicates are used on the result {@link IntersectionMatrix} - * of the RelateOp, the result may or not be affected by the - * choice of BoundaryNodeRule, depending on the exact nature of the pattern. - * For instance, {@link IntersectionMatrix#isIntersects()} is insensitive - * to the choice of BoundaryNodeRule, - * whereas {@link IntersectionMatrix#isTouches(int, int)} is affected by the rule chosen. - *

                      - * Note: custom Boundary Node Rules do not (currently) - * affect the results of other {@link Geometry} methods (such - * as {@link Geometry#getBoundary}. The results of - * these methods may not be consistent with the relationship computed by - * a custom Boundary Node Rule. - * - * @version 1.7 - */ -public class RelateOp - extends GeometryGraphOperation -{ - /** - * Computes the {@link IntersectionMatrix} for the spatial relationship - * between two {@link Geometry}s, using the default (OGC SFS) Boundary Node Rule - * - * @param a a Geometry to test - * @param b a Geometry to test - * @return the IntersectonMatrix for the spatial relationship between the geometries - */ - public static IntersectionMatrix relate(Geometry a, Geometry b) - { - RelateOp relOp = new RelateOp(a, b); - IntersectionMatrix im = relOp.getIntersectionMatrix(); - return im; - } - - /** - * Computes the {@link IntersectionMatrix} for the spatial relationship - * between two {@link Geometry}s using a specified Boundary Node Rule. - * - * @param a a Geometry to test - * @param b a Geometry to test - * @param boundaryNodeRule the Boundary Node Rule to use - * @return the IntersectonMatrix for the spatial relationship between the input geometries - */ - public static IntersectionMatrix relate(Geometry a, Geometry b, BoundaryNodeRule boundaryNodeRule) - { - RelateOp relOp = new RelateOp(a, b, boundaryNodeRule); - IntersectionMatrix im = relOp.getIntersectionMatrix(); - return im; - } - - private RelateComputer relate; - - /** - * Creates a new Relate operation, using the default (OGC SFS) Boundary Node Rule. - * - * @param g0 a Geometry to relate - * @param g1 another Geometry to relate - */ - public RelateOp(Geometry g0, Geometry g1) - { - super(g0, g1); - relate = new RelateComputer(arg); - } - - /** - * Creates a new Relate operation with a specified Boundary Node Rule. - * - * @param g0 a Geometry to relate - * @param g1 another Geometry to relate - * @param boundaryNodeRule the Boundary Node Rule to use - */ - public RelateOp(Geometry g0, Geometry g1, BoundaryNodeRule boundaryNodeRule) - { - super(g0, g1, boundaryNodeRule); - relate = new RelateComputer(arg); - } - - /** - * Gets the IntersectionMatrix for the spatial relationship - * between the input geometries. - * - * @return the IntersectonMatrix for the spatial relationship between the input geometries - */ - public IntersectionMatrix getIntersectionMatrix() - { - return relate.computeIM(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/union/CascadedPolygonUnion.java b/src/main/java/com/vividsolutions/jts/operation/union/CascadedPolygonUnion.java deleted file mode 100644 index 4282d96e44..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/union/CascadedPolygonUnion.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.union; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.index.strtree.STRtree; - - -/** - * Provides an efficient method of unioning a collection of - * {@link Polygonal} geometrys. - * The geometries are indexed using a spatial index, - * and unioned recursively in index order. - * For geometries with a high degree of overlap, - * this has the effect of reducing the number of vertices - * early in the process, which increases speed - * and robustness. - *

                      - * This algorithm is faster and more robust than - * the simple iterated approach of - * repeatedly unioning each polygon to a result geometry. - *

                      - * The buffer(0) trick is sometimes faster, but can be less robust and - * can sometimes take a long time to complete. - * This is particularly the case where there is a high degree of overlap - * between the polygons. In this case, buffer(0) is forced to compute - * with all line segments from the outset, - * whereas cascading can eliminate many segments - * at each stage of processing. - * The best situation for using buffer(0) is the trivial case - * where there is no overlap between the input geometries. - * However, this case is likely rare in practice. - * - * @author Martin Davis - * - */ -public class CascadedPolygonUnion -{ - /** - * Computes the union of - * a collection of {@link Polygonal} {@link Geometry}s. - * - * @param polys a collection of {@link Polygonal} {@link Geometry}s - */ - public static Geometry union(Collection polys) - { - CascadedPolygonUnion op = new CascadedPolygonUnion(polys); - return op.union(); - } - - private Collection inputPolys; - private GeometryFactory geomFactory = null; - - /** - * Creates a new instance to union - * the given collection of {@link Geometry}s. - * - * @param polys a collection of {@link Polygonal} {@link Geometry}s - */ - public CascadedPolygonUnion(Collection polys) - { - this.inputPolys = polys; - // guard against null input - if (inputPolys == null) - inputPolys = new ArrayList(); - } - - /** - * The effectiveness of the index is somewhat sensitive - * to the node capacity. - * Testing indicates that a smaller capacity is better. - * For an STRtree, 4 is probably a good number (since - * this produces 2x2 "squares"). - */ - private static final int STRTREE_NODE_CAPACITY = 4; - - /** - * Computes the union of the input geometries. - *

                      - * This method discards the input geometries as they are processed. - * In many input cases this reduces the memory retained - * as the operation proceeds. - * Optimal memory usage is achieved - * by disposing of the original input collection - * before calling this method. - * - * @return the union of the input geometries - * or null if no input geometries were provided - * @throws IllegalStateException if this method is called more than once - */ - public Geometry union() - { - if (inputPolys == null) - throw new IllegalStateException("union() method cannot be called twice"); - if (inputPolys.isEmpty()) - return null; - geomFactory = ((Geometry) inputPolys.iterator().next()).getFactory(); - - /** - * A spatial index to organize the collection - * into groups of close geometries. - * This makes unioning more efficient, since vertices are more likely - * to be eliminated on each round. - */ -// STRtree index = new STRtree(); - STRtree index = new STRtree(STRTREE_NODE_CAPACITY); - for (Iterator i = inputPolys.iterator(); i.hasNext(); ) { - Geometry item = (Geometry) i.next(); - index.insert(item.getEnvelopeInternal(), item); - } - // To avoiding holding memory remove references to the input geometries, - inputPolys = null; - - List itemTree = index.itemsTree(); -// printItemEnvelopes(itemTree); - Geometry unionAll = unionTree(itemTree); - return unionAll; - } - - private Geometry unionTree(List geomTree) - { - /** - * Recursively unions all subtrees in the list into single geometries. - * The result is a list of Geometrys only - */ - List geoms = reduceToGeometries(geomTree); -// Geometry union = bufferUnion(geoms); - Geometry union = binaryUnion(geoms); - - // print out union (allows visualizing hierarchy) -// System.out.println(union); - - return union; -// return repeatedUnion(geoms); -// return buffer0Union(geoms); - - } - - //======================================================== - /* - * The following methods are for experimentation only - */ - - private Geometry repeatedUnion(List geoms) - { - Geometry union = null; - for (Iterator i = geoms.iterator(); i.hasNext(); ) { - Geometry g = (Geometry) i.next(); - if (union == null) - union = (Geometry) g.clone(); - else - union = union.union(g); - } - return union; - } - - private Geometry bufferUnion(List geoms) - { - GeometryFactory factory = ((Geometry) geoms.get(0)).getFactory(); - Geometry gColl = factory.buildGeometry(geoms); - Geometry unionAll = gColl.buffer(0.0); - return unionAll; - } - - private Geometry bufferUnion(Geometry g0, Geometry g1) - { - GeometryFactory factory = g0.getFactory(); - Geometry gColl = factory.createGeometryCollection(new Geometry[] { g0, g1 } ); - Geometry unionAll = gColl.buffer(0.0); - return unionAll; - } - - //======================================= - - /** - * Unions a list of geometries - * by treating the list as a flattened binary tree, - * and performing a cascaded union on the tree. - */ - private Geometry binaryUnion(List geoms) - { - return binaryUnion(geoms, 0, geoms.size()); - } - - /** - * Unions a section of a list using a recursive binary union on each half - * of the section. - * - * @param geoms the list of geometries containing the section to union - * @param start the start index of the section - * @param end the index after the end of the section - * @return the union of the list section - */ - private Geometry binaryUnion(List geoms, int start, int end) - { - if (end - start <= 1) { - Geometry g0 = getGeometry(geoms, start); - return unionSafe(g0, null); - } - else if (end - start == 2) { - return unionSafe(getGeometry(geoms, start), getGeometry(geoms, start + 1)); - } - else { - // recurse on both halves of the list - int mid = (end + start) / 2; - Geometry g0 = binaryUnion(geoms, start, mid); - Geometry g1 = binaryUnion(geoms, mid, end); - return unionSafe(g0, g1); - } - } - - /** - * Gets the element at a given list index, or - * null if the index is out of range. - * - * @param list - * @param index - * @return the geometry at the given index - * or null if the index is out of range - */ - private static Geometry getGeometry(List list, int index) - { - if (index >= list.size()) return null; - return (Geometry) list.get(index); - } - - /** - * Reduces a tree of geometries to a list of geometries - * by recursively unioning the subtrees in the list. - * - * @param geomTree a tree-structured list of geometries - * @return a list of Geometrys - */ - private List reduceToGeometries(List geomTree) - { - List geoms = new ArrayList(); - for (Iterator i = geomTree.iterator(); i.hasNext(); ) { - Object o = i.next(); - Geometry geom = null; - if (o instanceof List) { - geom = unionTree((List) o); - } - else if (o instanceof Geometry) { - geom = (Geometry) o; - } - geoms.add(geom); - } - return geoms; - } - - /** - * Computes the union of two geometries, - * either or both of which may be null. - * - * @param g0 a Geometry - * @param g1 a Geometry - * @return the union of the input(s) - * or null if both inputs are null - */ - private Geometry unionSafe(Geometry g0, Geometry g1) - { - if (g0 == null && g1 == null) - return null; - - if (g0 == null) - return (Geometry) g1.clone(); - if (g1 == null) - return (Geometry) g0.clone(); - - return unionOptimized(g0, g1); - } - - private Geometry unionOptimized(Geometry g0, Geometry g1) - { - Envelope g0Env = g0.getEnvelopeInternal(); - Envelope g1Env = g1.getEnvelopeInternal(); - //* - if (! g0Env.intersects(g1Env)) - { - Geometry combo = GeometryCombiner.combine(g0, g1); -// System.out.println("Combined"); -// System.out.println(combo); - return combo; - } - //*/ -// System.out.println(g0.getNumGeometries() + ", " + g1.getNumGeometries()); - - if (g0.getNumGeometries() <= 1 && g1.getNumGeometries() <= 1) - return unionActual(g0, g1); - - // for testing... -// if (true) return g0.union(g1); - - Envelope commonEnv = g0Env.intersection(g1Env); - return unionUsingEnvelopeIntersection(g0, g1, commonEnv); - -// return UnionInteracting.union(g0, g1); - } - - - - /** - * Unions two polygonal geometries, restricting computation - * to the envelope intersection where possible. - * The case of MultiPolygons is optimized to union only - * the polygons which lie in the intersection of the two geometry's envelopes. - * Polygons outside this region can simply be combined with the union result, - * which is potentially much faster. - * This case is likely to occur often during cascaded union, and may also - * occur in real world data (such as unioning data for parcels on different street blocks). - * - * @param g0 a polygonal geometry - * @param g1 a polygonal geometry - * @param common the intersection of the envelopes of the inputs - * @return the union of the inputs - */ - private Geometry unionUsingEnvelopeIntersection(Geometry g0, Geometry g1, Envelope common) - { - List disjointPolys = new ArrayList(); - - Geometry g0Int = extractByEnvelope(common, g0, disjointPolys); - Geometry g1Int = extractByEnvelope(common, g1, disjointPolys); - -// System.out.println("# geoms in common: " + intersectingPolys.size()); - Geometry union = unionActual(g0Int, g1Int); - - disjointPolys.add(union); - Geometry overallUnion = GeometryCombiner.combine(disjointPolys); - - return overallUnion; - } - - private Geometry extractByEnvelope(Envelope env, Geometry geom, - List disjointGeoms) - { - List intersectingGeoms = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry elem = geom.getGeometryN(i); - if (elem.getEnvelopeInternal().intersects(env)) - intersectingGeoms.add(elem); - else - disjointGeoms.add(elem); - } - return geomFactory.buildGeometry(intersectingGeoms); - } - - /** - * Encapsulates the actual unioning of two polygonal geometries. - * - * @param g0 - * @param g1 - * @return - */ - private Geometry unionActual(Geometry g0, Geometry g1) - { - /* - System.out.println(g0.getNumGeometries() + ", " + g1.getNumGeometries()); - - if (g0.getNumGeometries() > 5) { - System.out.println(g0); - System.out.println(g1); - } - */ - - //return bufferUnion(g0, g1); - return restrictToPolygons(g0.union(g1)); - } - - /** - * Computes a {@link Geometry} containing only {@link Polygonal} components. - * Extracts the {@link Polygon}s from the input - * and returns them as an appropriate {@link Polygonal} geometry. - *

                      - * If the input is already Polygonal, it is returned unchanged. - *

                      - * A particular use case is to filter out non-polygonal components - * returned from an overlay operation. - * - * @param g the geometry to filter - * @return a Polygonal geometry - */ - private static Geometry restrictToPolygons(Geometry g) - { - if (g instanceof Polygonal) { - return g; - } - List polygons = PolygonExtracter.getPolygons(g); - if (polygons.size() == 1) - return (Polygon) polygons.get(0); - return g.getFactory().createMultiPolygon(GeometryFactory.toPolygonArray(polygons)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/union/PointGeometryUnion.java b/src/main/java/com/vividsolutions/jts/operation/union/PointGeometryUnion.java deleted file mode 100644 index caee28da36..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/union/PointGeometryUnion.java +++ /dev/null @@ -1,99 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.union; - -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import java.util.*; - -/** - * Computes the union of a {@link Puntal} geometry with - * another arbitrary {@link Geometry}. - * Does not copy any component geometries. - * - * @author mbdavis - * - */ -public class PointGeometryUnion -{ - public static Geometry union(Puntal pointGeom, Geometry otherGeom) - { - PointGeometryUnion unioner = new PointGeometryUnion(pointGeom, otherGeom); - return unioner.union(); - } - - private Geometry pointGeom; - private Geometry otherGeom; - private GeometryFactory geomFact; - - public PointGeometryUnion(Puntal pointGeom, Geometry otherGeom) - { - this.pointGeom = (Geometry) pointGeom; - this.otherGeom = otherGeom; - geomFact = otherGeom.getFactory(); - } - - public Geometry union() - { - PointLocator locater = new PointLocator(); - // use a set to eliminate duplicates, as required for union - Set exteriorCoords = new TreeSet(); - - for (int i =0 ; i < pointGeom.getNumGeometries(); i++) { - Point point = (Point) pointGeom.getGeometryN(i); - Coordinate coord = point.getCoordinate(); - int loc = locater.locate(coord, otherGeom); - if (loc == Location.EXTERIOR) - exteriorCoords.add(coord); - } - - // if no points are in exterior, return the other geom - if (exteriorCoords.size() == 0) - return otherGeom; - - // make a puntal geometry of appropriate size - Geometry ptComp = null; - Coordinate[] coords = CoordinateArrays.toCoordinateArray(exteriorCoords); - if (coords.length == 1) { - ptComp = geomFact.createPoint(coords[0]); - } - else { - ptComp = geomFact.createMultiPoint(coords); - } - - // add point component to the other geometry - return GeometryCombiner.combine(ptComp, otherGeom); - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/union/UnaryUnionOp.java b/src/main/java/com/vividsolutions/jts/operation/union/UnaryUnionOp.java deleted file mode 100644 index 47b1c1d7fd..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/union/UnaryUnionOp.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.union; - - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.operation.linemerge.LineMerger; -import com.vividsolutions.jts.operation.overlay.OverlayOp; -import com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp; - -/** - * Unions a Collection of {@link Geometry}s or a single Geometry - * (which may be a {@link GeoometryCollection}) together. - * By using this special-purpose operation over a collection of geometries - * it is possible to take advantage of various optimizations to improve performance. - * Heterogeneous {@link GeometryCollection}s are fully supported. - *

                      - * The result obeys the following contract: - *

                        - *
                      • Unioning a set of {@link Polygon}s has the effect of - * merging the areas (i.e. the same effect as - * iteratively unioning all individual polygons together). - * - *
                      • Unioning a set of {@link LineString}s has the effect of noding - * and dissolving the input linework. - * In this context "fully noded" means that there will be - * an endpoint or node in the result - * for every endpoint or line segment crossing in the input. - * "Dissolved" means that any duplicate (i.e. coincident) line segments or portions - * of line segments will be reduced to a single line segment in the result. - * This is consistent with the semantics of the - * {@link Geometry#union(Geometry)} operation. - * If merged linework is required, the {@link LineMerger} class can be used. - * - *
                      • Unioning a set of {@link Point}s has the effect of merging - * all identical points (producing a set with no duplicates). - *
                      - * - * UnaryUnion always operates on the individual components of MultiGeometries. - * So it is possible to use it to "clean" invalid self-intersecting MultiPolygons - * (although the polygon components must all still be individually valid.) - * - * @author mbdavis - * - */ -public class UnaryUnionOp -{ - /** - * Computes the geometric union of a {@link Collection} - * of {@link Geometry}s. - * - * @param geoms a collection of geometries - * @return the union of the geometries, - * or null if the input is empty - */ - public static Geometry union(Collection geoms) - { - UnaryUnionOp op = new UnaryUnionOp(geoms); - return op.union(); - } - - /** - * Computes the geometric union of a {@link Collection} - * of {@link Geometry}s. - * - * If no input geometries were provided but a {@link GeometryFactory} was provided, - * an empty {@link GeometryCollection} is returned. - * - * @param geoms a collection of geometries - * @param geomFact the geometry factory to use if the collection is empty - * @return the union of the geometries, - * or an empty GEOMETRYCOLLECTION - */ - public static Geometry union(Collection geoms, GeometryFactory geomFact) - { - UnaryUnionOp op = new UnaryUnionOp(geoms, geomFact); - return op.union(); - } - - /** - * Constructs a unary union operation for a {@link Geometry} - * (which may be a {@link GeometryCollection}). - * - * @param geom a geometry to union - * @return the union of the elements of the geometry - * or an empty GEOMETRYCOLLECTION - */ - public static Geometry union(Geometry geom) - { - UnaryUnionOp op = new UnaryUnionOp(geom); - return op.union(); - } - - private List polygons = new ArrayList(); - private List lines = new ArrayList(); - private List points = new ArrayList(); - - private GeometryFactory geomFact = null; - - /** - * Constructs a unary union operation for a {@link Collection} - * of {@link Geometry}s. - * - * @param geoms a collection of geometries - * @param geomFact the geometry factory to use if the collection is empty - */ - public UnaryUnionOp(Collection geoms, GeometryFactory geomFact) - { - this.geomFact = geomFact; - extract(geoms); - } - - /** - * Constructs a unary union operation for a {@link Collection} - * of {@link Geometry}s, using the {@link GeometryFactory} - * of the input geometries. - * - * @param geoms a collection of geometries - */ - public UnaryUnionOp(Collection geoms) - { - extract(geoms); - } - - /** - * Constructs a unary union operation for a {@link Geometry} - * (which may be a {@link GeometryCollection}). - * @param geom - */ - public UnaryUnionOp(Geometry geom) - { - extract(geom); - } - - private void extract(Collection geoms) - { - for (Iterator i = geoms.iterator(); i.hasNext();) { - Geometry geom = (Geometry) i.next(); - extract(geom); - } - } - - private void extract(Geometry geom) - { - if (geomFact == null) - geomFact = geom.getFactory(); - - /* - PolygonExtracter.getPolygons(geom, polygons); - LineStringExtracter.getLines(geom, lines); - PointExtracter.getPoints(geom, points); - */ - GeometryExtracter.extract(geom, Polygon.class, polygons); - GeometryExtracter.extract(geom, LineString.class, lines); - GeometryExtracter.extract(geom, Point.class, points); - } - - /** - * Gets the union of the input geometries. - * If no input geometries were provided but a {@link GeometryFactory} was provided, - * an empty {@link GeometryCollection} is returned. - * Otherwise, the return value is null. - * - * @return a Geometry containing the union, - * or an empty GEOMETRYCOLLECTION if no geometries were provided in the input, - * or null if no GeometryFactory was provided - */ - public Geometry union() - { - if (geomFact == null) { - return null; - } - - /** - * For points and lines, only a single union operation is - * required, since the OGC model allowings self-intersecting - * MultiPoint and MultiLineStrings. - * This is not the case for polygons, so Cascaded Union is required. - */ - Geometry unionPoints = null; - if (points.size() > 0) { - Geometry ptGeom = geomFact.buildGeometry(points); - unionPoints = unionNoOpt(ptGeom); - } - - Geometry unionLines = null; - if (lines.size() > 0) { - Geometry lineGeom = geomFact.buildGeometry(lines); - unionLines = unionNoOpt(lineGeom); - } - - Geometry unionPolygons = null; - if (polygons.size() > 0) { - unionPolygons = CascadedPolygonUnion.union(polygons); - } - - /** - * Performing two unions is somewhat inefficient, - * but is mitigated by unioning lines and points first - */ - Geometry unionLA = unionWithNull(unionLines, unionPolygons); - Geometry union = null; - if (unionPoints == null) - union = unionLA; - else if (unionLA == null) - union = unionPoints; - else - union = PointGeometryUnion.union((Puntal) unionPoints, unionLA); - - if (union == null) - return geomFact.createGeometryCollection(null); - - return union; - } - - /** - * Computes the union of two geometries, - * either of both of which may be null. - * - * @param g0 a Geometry - * @param g1 a Geometry - * @return the union of the input(s) - * or null if both inputs are null - */ - private Geometry unionWithNull(Geometry g0, Geometry g1) - { - if (g0 == null && g1 == null) - return null; - - if (g1 == null) - return g0; - if (g0 == null) - return g1; - - return g0.union(g1); - } - - /** - * Computes a unary union with no extra optimization, - * and no short-circuiting. - * Due to the way the overlay operations - * are implemented, this is still efficient in the case of linear - * and puntal geometries. - * Uses robust version of overlay operation - * to ensure identical behaviour to the union(Geometry) operation. - * - * @param g0 a geometry - * @return the union of the input geometry - */ - private Geometry unionNoOpt(Geometry g0) - { - Geometry empty = geomFact.createPoint((Coordinate) null); - return SnapIfNeededOverlayOp.overlayOp(g0, empty, OverlayOp.UNION); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/union/UnionInteracting.java b/src/main/java/com/vividsolutions/jts/operation/union/UnionInteracting.java deleted file mode 100644 index c321424fcc..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/union/UnionInteracting.java +++ /dev/null @@ -1,152 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.operation.union; - -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.GeometryCombiner; - -/** - * Experimental code to union MultiPolygons - * with processing limited to the elements which actually interact. - * - * Not currently used, since it doesn't seem to offer much of a performance advantage. - * - * @author mbdavis - * - */ -public class UnionInteracting -{ - public static Geometry union(Geometry g0, Geometry g1) - { - UnionInteracting uue = new UnionInteracting(g0, g1); - return uue.union(); - } - - - private GeometryFactory geomFactory; - - private Geometry g0; - private Geometry g1; - - private boolean[] interacts0; - private boolean[] interacts1; - - public UnionInteracting(Geometry g0, Geometry g1) - { - this.g0 = g0; - this.g1 = g1; - geomFactory = g0.getFactory(); - interacts0 = new boolean[g0.getNumGeometries()]; - interacts1 = new boolean[g1.getNumGeometries()]; - } - - public Geometry union() - { - computeInteracting(); - - // check for all interacting or none interacting! - - Geometry int0 = extractElements(g0, interacts0, true); - Geometry int1 = extractElements(g1, interacts1, true); - -// System.out.println(int0); -// System.out.println(int1); - - if (int0.isEmpty() || int1.isEmpty()) { - System.out.println("found empty!"); -// computeInteracting(); - } -// if (! int0.isValid()) { - //System.out.println(int0); - //throw new RuntimeException("invalid geom!"); -// } - - Geometry union = int0.union(int1); - //Geometry union = bufferUnion(int0, int1); - - Geometry disjoint0 = extractElements(g0, interacts0, false); - Geometry disjoint1 = extractElements(g1, interacts1, false); - - Geometry overallUnion = GeometryCombiner.combine(union, disjoint0, disjoint1); - - return overallUnion; - - } - - private Geometry bufferUnion(Geometry g0, Geometry g1) - { - GeometryFactory factory = g0.getFactory(); - Geometry gColl = factory.createGeometryCollection(new Geometry[] { g0, g1 } ); - Geometry unionAll = gColl.buffer(0.0); - return unionAll; - } - - private void computeInteracting() - { - for (int i = 0; i < g0.getNumGeometries(); i++) { - Geometry elem = g0.getGeometryN(i); - interacts0[i] = computeInteracting(elem); - } - } - - private boolean computeInteracting(Geometry elem0) - { - boolean interactsWithAny = false; - for (int i = 0; i < g1.getNumGeometries(); i++) { - Geometry elem1 = g1.getGeometryN(i); - boolean interacts = elem1.getEnvelopeInternal().intersects(elem0.getEnvelopeInternal()); - if (interacts) interacts1[i] = true; - if (interacts) - interactsWithAny = true; - } - return interactsWithAny; - } - - private Geometry extractElements(Geometry geom, - boolean[] interacts, boolean isInteracting) - { - List extractedGeoms = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry elem = geom.getGeometryN(i); - if (interacts[i] == isInteracting) - extractedGeoms.add(elem); - } - return geomFactory.buildGeometry(extractedGeoms); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java deleted file mode 100644 index 42c3e183ff..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java +++ /dev/null @@ -1,239 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.operation.overlay.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * This class tests that the interior of an area {@link Geometry} - * ( {@link Polygon} or {@link MultiPolygon} ) - * is connected. - * This can happen if: - *
                        - *
                      • a shell self-intersects - *
                      • one or more holes form a connected chain touching a shell at two different points - *
                      • one or more holes form a ring around a subset of the interior - *
                      - * If a disconnected situation is found the location of the problem is recorded. - * - * @version 1.7 - */ -public class ConnectedInteriorTester { - - public static Coordinate findDifferentPoint(Coordinate[] coord, Coordinate pt) - { - for (int i = 0; i < coord.length; i++) { - if (! coord[i].equals(pt)) - return coord[i]; - } - return null; - } - - private GeometryFactory geometryFactory = new GeometryFactory(); - - private GeometryGraph geomGraph; - // save a coordinate for any disconnected interior found - // the coordinate will be somewhere on the ring surrounding the disconnected interior - private Coordinate disconnectedRingcoord; - - public ConnectedInteriorTester(GeometryGraph geomGraph) - { - this.geomGraph = geomGraph; - } - - public Coordinate getCoordinate() { return disconnectedRingcoord; } - - public boolean isInteriorsConnected() - { - // node the edges, in case holes touch the shell - List splitEdges = new ArrayList(); - geomGraph.computeSplitEdges(splitEdges); - - // form the edges into rings - PlanarGraph graph = new PlanarGraph(new OverlayNodeFactory()); - graph.addEdges(splitEdges); - setInteriorEdgesInResult(graph); - graph.linkResultDirectedEdges(); - List edgeRings = buildEdgeRings(graph.getEdgeEnds()); - - /** - * Mark all the edges for the edgeRings corresponding to the shells - * of the input polygons. Note only ONE ring gets marked for each shell. - */ - visitShellInteriors(geomGraph.getGeometry(), graph); - - /** - * If there are any unvisited shell edges - * (i.e. a ring which is not a hole and which has the interior - * of the parent area on the RHS) - * this means that one or more holes must have split the interior of the - * polygon into at least two pieces. The polygon is thus invalid. - */ - return ! hasUnvisitedShellEdge(edgeRings); - } - - private void setInteriorEdgesInResult(PlanarGraph graph) - { - for (Iterator it = graph.getEdgeEnds().iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - if (de.getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { - de.setInResult(true); - } - } - } - - /** - * Form DirectedEdges in graph into Minimal EdgeRings. - * (Minimal Edgerings must be used, because only they are guaranteed to provide - * a correct isHole computation) - */ - private List buildEdgeRings(Collection dirEdges) - { - List edgeRings = new ArrayList(); - for (Iterator it = dirEdges.iterator(); it.hasNext(); ) { - DirectedEdge de = (DirectedEdge) it.next(); - // if this edge has not yet been processed - if (de.isInResult() - && de.getEdgeRing() == null) { - MaximalEdgeRing er = new MaximalEdgeRing(de, geometryFactory); - - er.linkDirectedEdgesForMinimalEdgeRings(); - List minEdgeRings = er.buildMinimalRings(); - edgeRings.addAll(minEdgeRings); - } - } - return edgeRings; - } - - /** - * Mark all the edges for the edgeRings corresponding to the shells - * of the input polygons. - * Only ONE ring gets marked for each shell - if there are others which remain unmarked - * this indicates a disconnected interior. - */ - private void visitShellInteriors(Geometry g, PlanarGraph graph) - { - if (g instanceof Polygon) { - Polygon p = (Polygon) g; - visitInteriorRing(p.getExteriorRing(), graph); - } - if (g instanceof MultiPolygon) { - MultiPolygon mp = (MultiPolygon) g; - for (int i = 0; i < mp.getNumGeometries(); i++) { - Polygon p = (Polygon) mp.getGeometryN(i); - visitInteriorRing(p.getExteriorRing(), graph); - } - } - } - - private void visitInteriorRing(LineString ring, PlanarGraph graph) - { - Coordinate[] pts = ring.getCoordinates(); - Coordinate pt0 = pts[0]; - /** - * Find first point in coord list different to initial point. - * Need special check since the first point may be repeated. - */ - Coordinate pt1 = findDifferentPoint(pts, pt0); - Edge e = graph.findEdgeInSameDirection(pt0, pt1); - DirectedEdge de = (DirectedEdge) graph.findEdgeEnd(e); - DirectedEdge intDe = null; - if (de.getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { - intDe = de; - } - else if (de.getSym().getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { - intDe = de.getSym(); - } - Assert.isTrue(intDe != null, "unable to find dirEdge with Interior on RHS"); - - visitLinkedDirectedEdges(intDe); - } - - protected void visitLinkedDirectedEdges(DirectedEdge start) - { - DirectedEdge startDe = start; - DirectedEdge de = start; - do { - Assert.isTrue(de != null, "found null Directed Edge"); - de.setVisited(true); - de = de.getNext(); - } while (de != startDe); - } - - /** - * Check if any shell ring has an unvisited edge. - * A shell ring is a ring which is not a hole and which has the interior - * of the parent area on the RHS. - * (Note that there may be non-hole rings with the interior on the LHS, - * since the interior of holes will also be polygonized into CW rings - * by the linkAllDirectedEdges() step) - * - * @return true if there is an unvisited edge in a non-hole ring - */ - private boolean hasUnvisitedShellEdge(List edgeRings) - { - for (int i = 0; i < edgeRings.size(); i++) { - EdgeRing er = (EdgeRing) edgeRings.get(i); - // don't check hole rings - if (er.isHole()) - continue; - List edges = er.getEdges(); - DirectedEdge de = (DirectedEdge) edges.get(0); - // don't check CW rings which are holes - // (MD - this check may now be irrelevant) - if (de.getLabel().getLocation(0, Position.RIGHT) != Location.INTERIOR) continue; - - /** - * the edgeRing is CW ring which surrounds the INT of the area, so check all - * edges have been visited. If any are unvisited, this is a disconnected part of the interior - */ - for (int j = 0; j < edges.size(); j++) { - de = (DirectedEdge) edges.get(j); -//Debug.print("visted? "); Debug.println(de); - if (! de.isVisited()) { -//Debug.print("not visited "); Debug.println(de); - disconnectedRingcoord = de.getCoordinate(); - return true; - } - } - } - return false; - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java deleted file mode 100644 index c838a9c66b..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java +++ /dev/null @@ -1,162 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geomgraph.index.SegmentIntersector; -import com.vividsolutions.jts.operation.relate.*; -import com.vividsolutions.jts.util.*; - -/** - * Checks that a {@link GeometryGraph} representing an area - * (a {@link Polygon} or {@link MultiPolygon} ) - * has consistent semantics for area geometries. - * This check is required for any reasonable polygonal model - * (including the OGC-SFS model, as well as models which allow ring self-intersection at single points) - *

                      - * Checks include: - *

                        - *
                      • test for rings which properly intersect - * (but not for ring self-intersection, or intersections at vertices) - *
                      • test for consistent labelling at all node points - * (this detects vertex intersections with invalid topology, - * i.e. where the exterior side of an edge lies in the interior of the area) - *
                      • test for duplicate rings - *
                      - * If an inconsistency is found the location of the problem - * is recorded and is available to the caller. - * - * @version 1.7 - */ -public class ConsistentAreaTester { - - private final LineIntersector li = new RobustLineIntersector(); - private GeometryGraph geomGraph; - private RelateNodeGraph nodeGraph = new RelateNodeGraph(); - - // the intersection point found (if any) - private Coordinate invalidPoint; - - /** - * Creates a new tester for consistent areas. - * - * @param geomGraph the topology graph of the area geometry - */ - public ConsistentAreaTester(GeometryGraph geomGraph) - { - this.geomGraph = geomGraph; - } - - /** - * @return the intersection point, or null if none was found - */ - public Coordinate getInvalidPoint() { return invalidPoint; } - - /** - * Check all nodes to see if their labels are consistent with area topology. - * - * @return true if this area has a consistent node labelling - */ - public boolean isNodeConsistentArea() - { - /** - * To fully check validity, it is necessary to - * compute ALL intersections, including self-intersections within a single edge. - */ - SegmentIntersector intersector = geomGraph.computeSelfNodes(li, true); - if (intersector.hasProperIntersection()) { - invalidPoint = intersector.getProperIntersectionPoint(); - return false; - } - - nodeGraph.build(geomGraph); - - return isNodeEdgeAreaLabelsConsistent(); - } - - /** - * Check all nodes to see if their labels are consistent. - * If any are not, return false - * - * @return true if the edge area labels are consistent at this node - */ - private boolean isNodeEdgeAreaLabelsConsistent() - { - for (Iterator nodeIt = nodeGraph.getNodeIterator(); nodeIt.hasNext(); ) { - RelateNode node = (RelateNode) nodeIt.next(); - if (! node.getEdges().isAreaLabelsConsistent(geomGraph)) { - invalidPoint = (Coordinate) node.getCoordinate().clone(); - return false; - } - } - return true; - } - - /** - * Checks for two duplicate rings in an area. - * Duplicate rings are rings that are topologically equal - * (that is, which have the same sequence of points up to point order). - * If the area is topologically consistent (determined by calling the - * isNodeConsistentArea, - * duplicate rings can be found by checking for EdgeBundles which contain - * more than one EdgeEnd. - * (This is because topologically consistent areas cannot have two rings sharing - * the same line segment, unless the rings are equal). - * The start point of one of the equal rings will be placed in - * invalidPoint. - * - * @return true if this area Geometry is topologically consistent but has two duplicate rings - */ - public boolean hasDuplicateRings() - { - for (Iterator nodeIt = nodeGraph.getNodeIterator(); nodeIt.hasNext(); ) { - RelateNode node = (RelateNode) nodeIt.next(); - for (Iterator i = node.getEdges().iterator(); i.hasNext(); ) { - EdgeEndBundle eeb = (EdgeEndBundle) i.next(); - if (eeb.getEdgeEnds().size() > 1) { - invalidPoint = eeb.getEdge().getCoordinate(0); - return true; - } - } - } - return false; - } - - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java deleted file mode 100644 index 4426794196..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.index.SpatialIndex; -import com.vividsolutions.jts.index.strtree.STRtree; -import com.vividsolutions.jts.util.*; - -/** - * Tests whether any of a set of {@link LinearRing}s are - * nested inside another ring in the set, using a spatial - * index to speed up the comparisons. - * - * @version 1.7 - */ -public class IndexedNestedRingTester -{ - private GeometryGraph graph; // used to find non-node vertices - private List rings = new ArrayList(); - private Envelope totalEnv = new Envelope(); - private SpatialIndex index; - private Coordinate nestedPt; - - public IndexedNestedRingTester(GeometryGraph graph) - { - this.graph = graph; - } - - public Coordinate getNestedPoint() { return nestedPt; } - - public void add(LinearRing ring) - { - rings.add(ring); - totalEnv.expandToInclude(ring.getEnvelopeInternal()); - } - - public boolean isNonNested() - { - buildIndex(); - - for (int i = 0; i < rings.size(); i++) { - LinearRing innerRing = (LinearRing) rings.get(i); - Coordinate[] innerRingPts = innerRing.getCoordinates(); - - List results = index.query(innerRing.getEnvelopeInternal()); -//System.out.println(results.size()); - for (int j = 0; j < results.size(); j++) { - LinearRing searchRing = (LinearRing) results.get(j); - Coordinate[] searchRingPts = searchRing.getCoordinates(); - - if (innerRing == searchRing) - continue; - - if (! innerRing.getEnvelopeInternal().intersects(searchRing.getEnvelopeInternal())) - continue; - - Coordinate innerRingPt = IsValidOp.findPtNotNode(innerRingPts, searchRing, graph); - - /** - * If no non-node pts can be found, this means - * that the searchRing touches ALL of the innerRing vertices. - * This indicates an invalid polygon, since either - * the two holes create a disconnected interior, - * or they touch in an infinite number of points - * (i.e. along a line segment). - * Both of these cases are caught by other tests, - * so it is safe to simply skip this situation here. - */ - if (innerRingPt == null) - continue; - - boolean isInside = CGAlgorithms.isPointInRing(innerRingPt, searchRingPts); - if (isInside) { - nestedPt = innerRingPt; - return false; - } - } - } - return true; - } - - private void buildIndex() - { - index = new STRtree(); - - for (int i = 0; i < rings.size(); i++) { - LinearRing ring = (LinearRing) rings.get(i); - Envelope env = ring.getEnvelopeInternal(); - index.insert(env, ring); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/IsValidOp.java b/src/main/java/com/vividsolutions/jts/operation/valid/IsValidOp.java deleted file mode 100644 index 367eec4618..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/IsValidOp.java +++ /dev/null @@ -1,618 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.*; - -/** - * Implements the algorithms required to compute the isValid() method - * for {@link Geometry}s. - * See the documentation for the various geometry types for a specification of validity. - * - * @version 1.7 - */ -public class IsValidOp -{ - /** - * Tests whether a {@link Geometry} is valid. - * @param geom the Geometry to test - * @return true if the geometry is valid - */ - public static boolean isValid(Geometry geom) - { - IsValidOp isValidOp = new IsValidOp(geom); - return isValidOp.isValid(); - } - - /** - * Checks whether a coordinate is valid for processing. - * Coordinates are valid iff their x and y ordinates are in the - * range of the floating point representation. - * - * @param coord the coordinate to validate - * @return true if the coordinate is valid - */ - public static boolean isValid(Coordinate coord) - { - if (Double.isNaN(coord.x)) return false; - if (Double.isInfinite(coord.x)) return false; - if (Double.isNaN(coord.y)) return false; - if (Double.isInfinite(coord.y)) return false; - return true; - } - /** - * Find a point from the list of testCoords - * that is NOT a node in the edge for the list of searchCoords - * - * @return the point found, or null if none found - */ - public static Coordinate findPtNotNode( - Coordinate[] testCoords, - LinearRing searchRing, - GeometryGraph graph) - { - // find edge corresponding to searchRing. - Edge searchEdge = graph.findEdge(searchRing); - // find a point in the testCoords which is not a node of the searchRing - EdgeIntersectionList eiList = searchEdge.getEdgeIntersectionList(); - // somewhat inefficient - is there a better way? (Use a node map, for instance?) - for (int i = 0 ; i < testCoords.length; i++) { - Coordinate pt = testCoords[i]; - if (! eiList.isIntersection(pt)) - return pt; - } - return null; - } - - private Geometry parentGeometry; // the base Geometry to be validated - /** - * If the following condition is TRUE JTS will validate inverted shells and exverted holes - * (the ESRI SDE model) - */ - private boolean isSelfTouchingRingFormingHoleValid = false; - private TopologyValidationError validErr; - - public IsValidOp(Geometry parentGeometry) - { - this.parentGeometry = parentGeometry; - } - - /** - * Sets whether polygons using Self-Touching Rings to form - * holes are reported as valid. - * If this flag is set, the following Self-Touching conditions - * are treated as being valid: - *
                        - *
                      • the shell ring self-touches to create a hole touching the shell - *
                      • a hole ring self-touches to create two holes touching at a point - *
                      - *

                      - * The default (following the OGC SFS standard) - * is that this condition is not valid (false). - *

                      - * This does not affect whether Self-Touching Rings - * disconnecting the polygon interior are considered valid - * (these are considered to be invalid under the SFS, and many other - * spatial models as well). - * This includes "bow-tie" shells, - * which self-touch at a single point causing the interior to - * be disconnected, - * and "C-shaped" holes which self-touch at a single point causing an island to be formed. - * - * @param isValid states whether geometry with this condition is valid - */ - public void setSelfTouchingRingFormingHoleValid(boolean isValid) - { - isSelfTouchingRingFormingHoleValid = isValid; - } - - /** - * Computes the validity of the geometry, - * and returns true if it is valid. - * - * @return true if the geometry is valid - */ - public boolean isValid() - { - checkValid(parentGeometry); - return validErr == null; - } - - /** - * Computes the validity of the geometry, - * and if not valid returns the validation error for the geometry, - * or null if the geometry is valid. - * - * @return the validation error, if the geometry is invalid - * or null if the geometry is valid - */ - public TopologyValidationError getValidationError() - { - checkValid(parentGeometry); - return validErr; - } - - private void checkValid(Geometry g) - { - validErr = null; - - // empty geometries are always valid! - if (g.isEmpty()) return; - - if (g instanceof Point) checkValid((Point) g); - else if (g instanceof MultiPoint) checkValid((MultiPoint) g); - // LineString also handles LinearRings - else if (g instanceof LinearRing) checkValid( (LinearRing) g); - else if (g instanceof LineString) checkValid( (LineString) g); - else if (g instanceof Polygon) checkValid( (Polygon) g); - else if (g instanceof MultiPolygon) checkValid( (MultiPolygon) g); - else if (g instanceof GeometryCollection) checkValid( (GeometryCollection) g); - else throw new UnsupportedOperationException(g.getClass().getName()); - } - - /** - * Checks validity of a Point. - */ - private void checkValid(Point g) - { - checkInvalidCoordinates(g.getCoordinates()); - } - /** - * Checks validity of a MultiPoint. - */ - private void checkValid(MultiPoint g) - { - checkInvalidCoordinates(g.getCoordinates()); - } - - /** - * Checks validity of a LineString. Almost anything goes for linestrings! - */ - private void checkValid(LineString g) - { - checkInvalidCoordinates(g.getCoordinates()); - if (validErr != null) return; - GeometryGraph graph = new GeometryGraph(0, g); - checkTooFewPoints(graph); - } - /** - * Checks validity of a LinearRing. - */ - private void checkValid(LinearRing g) - { - checkInvalidCoordinates(g.getCoordinates()); - if (validErr != null) return; - checkClosedRing(g); - if (validErr != null) return; - - GeometryGraph graph = new GeometryGraph(0, g); - checkTooFewPoints(graph); - if (validErr != null) return; - LineIntersector li = new RobustLineIntersector(); - graph.computeSelfNodes(li, true); - checkNoSelfIntersectingRings(graph); - } - - /** - * Checks the validity of a polygon. - * Sets the validErr flag. - */ - private void checkValid(Polygon g) - { - checkInvalidCoordinates(g); - if (validErr != null) return; - checkClosedRings(g); - if (validErr != null) return; - - GeometryGraph graph = new GeometryGraph(0, g); - - checkTooFewPoints(graph); - if (validErr != null) return; - checkConsistentArea(graph); - if (validErr != null) return; - - if (! isSelfTouchingRingFormingHoleValid) { - checkNoSelfIntersectingRings(graph); - if (validErr != null) return; - } - checkHolesInShell(g, graph); - if (validErr != null) return; - //SLOWcheckHolesNotNested(g); - checkHolesNotNested(g, graph); - if (validErr != null) return; - checkConnectedInteriors(graph); - } - - private void checkValid(MultiPolygon g) - { - for (int i = 0; i < g.getNumGeometries(); i++) { - Polygon p = (Polygon) g.getGeometryN(i); - checkInvalidCoordinates(p); - if (validErr != null) return; - checkClosedRings(p); - if (validErr != null) return; - } - - GeometryGraph graph = new GeometryGraph(0, g); - - checkTooFewPoints(graph); - if (validErr != null) return; - checkConsistentArea(graph); - if (validErr != null) return; - if (! isSelfTouchingRingFormingHoleValid) { - checkNoSelfIntersectingRings(graph); - if (validErr != null) return; - } - for (int i = 0; i < g.getNumGeometries(); i++) { - Polygon p = (Polygon) g.getGeometryN(i); - checkHolesInShell(p, graph); - if (validErr != null) return; - } - for (int i = 0; i < g.getNumGeometries(); i++) { - Polygon p = (Polygon) g.getGeometryN(i); - checkHolesNotNested(p, graph); - if (validErr != null) return; - } - checkShellsNotNested(g, graph); - if (validErr != null) return; - checkConnectedInteriors(graph); - } - - private void checkValid(GeometryCollection gc) - { - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - checkValid(g); - if (validErr != null) return; - } - } - - private void checkInvalidCoordinates(Coordinate[] coords) - { - for (int i = 0; i < coords.length; i++) { - if (! isValid(coords[i])) { - validErr = new TopologyValidationError( - TopologyValidationError.INVALID_COORDINATE, - coords[i]); - return; - } - } - } - - private void checkInvalidCoordinates(Polygon poly) - { - checkInvalidCoordinates(poly.getExteriorRing().getCoordinates()); - if (validErr != null) return; - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - checkInvalidCoordinates(poly.getInteriorRingN(i).getCoordinates()); - if (validErr != null) return; - } - } - - private void checkClosedRings(Polygon poly) - { - checkClosedRing((LinearRing) poly.getExteriorRing()); - if (validErr != null) return; - for (int i = 0; i < poly.getNumInteriorRing(); i++) { - checkClosedRing((LinearRing) poly.getInteriorRingN(i)); - if (validErr != null) return; - } - } - - private void checkClosedRing(LinearRing ring) - { - if (! ring.isClosed() ) { - Coordinate pt = null; - if (ring.getNumPoints() >= 1) - pt = ring.getCoordinateN(0); - validErr = new TopologyValidationError( - TopologyValidationError.RING_NOT_CLOSED, - pt); - } - } - - private void checkTooFewPoints(GeometryGraph graph) - { - if (graph.hasTooFewPoints()) { - validErr = new TopologyValidationError( - TopologyValidationError.TOO_FEW_POINTS, - graph.getInvalidPoint()); - return; - } - } - - /** - * Checks that the arrangement of edges in a polygonal geometry graph - * forms a consistent area. - * - * @param graph - * - * @see ConsistentAreaTester - */ - private void checkConsistentArea(GeometryGraph graph) - { - ConsistentAreaTester cat = new ConsistentAreaTester(graph); - boolean isValidArea = cat.isNodeConsistentArea(); - if (! isValidArea) { - validErr = new TopologyValidationError( - TopologyValidationError.SELF_INTERSECTION, - cat.getInvalidPoint()); - return; - } - if (cat.hasDuplicateRings()) { - validErr = new TopologyValidationError( - TopologyValidationError.DUPLICATE_RINGS, - cat.getInvalidPoint()); - } - } - - /** - * Check that there is no ring which self-intersects (except of course at its endpoints). - * This is required by OGC topology rules (but not by other models - * such as ESRI SDE, which allow inverted shells and exverted holes). - * - * @param graph the topology graph of the geometry - */ - private void checkNoSelfIntersectingRings(GeometryGraph graph) - { - for (Iterator i = graph.getEdgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - checkNoSelfIntersectingRing(e.getEdgeIntersectionList()); - if (validErr != null) - return; - } - } - - /** - * Check that a ring does not self-intersect, except at its endpoints. - * Algorithm is to count the number of times each node along edge occurs. - * If any occur more than once, that must be a self-intersection. - */ - private void checkNoSelfIntersectingRing(EdgeIntersectionList eiList) - { - Set nodeSet = new TreeSet(); - boolean isFirst = true; - for (Iterator i = eiList.iterator(); i.hasNext(); ) { - EdgeIntersection ei = (EdgeIntersection) i.next(); - if (isFirst) { - isFirst = false; - continue; - } - if (nodeSet.contains(ei.coord)) { - validErr = new TopologyValidationError( - TopologyValidationError.RING_SELF_INTERSECTION, - ei.coord); - return; - } - else { - nodeSet.add(ei.coord); - } - } - } - - /** - * Tests that each hole is inside the polygon shell. - * This routine assumes that the holes have previously been tested - * to ensure that all vertices lie on the shell oon the same side of it - * (i.e that the hole rings do not cross the shell ring). - * In other words, this test is only correct if the ConsistentArea test is passed first. - * Given this, a simple point-in-polygon test of a single point in the hole can be used, - * provided the point is chosen such that it does not lie on the shell. - * - * @param p the polygon to be tested for hole inclusion - * @param graph a GeometryGraph incorporating the polygon - */ - private void checkHolesInShell(Polygon p, GeometryGraph graph) - { - LinearRing shell = (LinearRing) p.getExteriorRing(); - - //PointInRing pir = new SimplePointInRing(shell); - //PointInRing pir = new SIRtreePointInRing(shell); - PointInRing pir = new MCPointInRing(shell); - - for (int i = 0; i < p.getNumInteriorRing(); i++) { - - LinearRing hole = (LinearRing) p.getInteriorRingN(i); - Coordinate holePt = findPtNotNode(hole.getCoordinates(), shell, graph); - /** - * If no non-node hole vertex can be found, the hole must - * split the polygon into disconnected interiors. - * This will be caught by a subsequent check. - */ - if (holePt == null) return; - - boolean outside = ! pir.isInside(holePt); - if ( outside ) { - validErr = new TopologyValidationError( - TopologyValidationError.HOLE_OUTSIDE_SHELL, - holePt); - return; - } - } - } - - /** - * Tests that no hole is nested inside another hole. - * This routine assumes that the holes are disjoint. - * To ensure this, holes have previously been tested - * to ensure that: - *

                        - *
                      • they do not partially overlap - * (checked by checkRelateConsistency) - *
                      • they are not identical - * (checked by checkRelateConsistency) - *
                      - */ - private void checkHolesNotNested(Polygon p, GeometryGraph graph) - { - IndexedNestedRingTester nestedTester = new IndexedNestedRingTester(graph); - //SimpleNestedRingTester nestedTester = new SimpleNestedRingTester(arg[0]); - //SweeplineNestedRingTester nestedTester = new SweeplineNestedRingTester(arg[0]); - - for (int i = 0; i < p.getNumInteriorRing(); i++) { - LinearRing innerHole = (LinearRing) p.getInteriorRingN(i); - nestedTester.add(innerHole); - } - boolean isNonNested = nestedTester.isNonNested(); - if ( ! isNonNested ) { - validErr = new TopologyValidationError( - TopologyValidationError.NESTED_HOLES, - nestedTester.getNestedPoint()); - } - } - - /** - * Tests that no element polygon is wholly in the interior of another element polygon. - *

                      - * Preconditions: - *

                        - *
                      • shells do not partially overlap - *
                      • shells do not touch along an edge - *
                      • no duplicate rings exist - *
                      - * This routine relies on the fact that while polygon shells may touch at one or - * more vertices, they cannot touch at ALL vertices. - */ - private void checkShellsNotNested(MultiPolygon mp, GeometryGraph graph) - { - for (int i = 0; i < mp.getNumGeometries(); i++) { - Polygon p = (Polygon) mp.getGeometryN(i); - LinearRing shell = (LinearRing) p.getExteriorRing(); - for (int j = 0; j < mp.getNumGeometries(); j++) { - if (i == j) continue; - Polygon p2 = (Polygon) mp.getGeometryN(j); - checkShellNotNested(shell, p2, graph); - if (validErr != null) return; - } - } - } - - /** - * Check if a shell is incorrectly nested within a polygon. This is the case - * if the shell is inside the polygon shell, but not inside a polygon hole. - * (If the shell is inside a polygon hole, the nesting is valid.) - *

                      - * The algorithm used relies on the fact that the rings must be properly contained. - * E.g. they cannot partially overlap (this has been previously checked by - * checkRelateConsistency ) - */ - private void checkShellNotNested(LinearRing shell, Polygon p, GeometryGraph graph) - { - Coordinate[] shellPts = shell.getCoordinates(); - // test if shell is inside polygon shell - LinearRing polyShell = (LinearRing) p.getExteriorRing(); - Coordinate[] polyPts = polyShell.getCoordinates(); - Coordinate shellPt = findPtNotNode(shellPts, polyShell, graph); - // if no point could be found, we can assume that the shell is outside the polygon - if (shellPt == null) - return; - boolean insidePolyShell = CGAlgorithms.isPointInRing(shellPt, polyPts); - if (! insidePolyShell) return; - - // if no holes, this is an error! - if (p.getNumInteriorRing() <= 0) { - validErr = new TopologyValidationError( - TopologyValidationError.NESTED_SHELLS, - shellPt); - return; - } - - /** - * Check if the shell is inside one of the holes. - * This is the case if one of the calls to checkShellInsideHole - * returns a null coordinate. - * Otherwise, the shell is not properly contained in a hole, which is an error. - */ - Coordinate badNestedPt = null; - for (int i = 0; i < p.getNumInteriorRing(); i++) { - LinearRing hole = (LinearRing) p.getInteriorRingN(i); - badNestedPt = checkShellInsideHole(shell, hole, graph); - if (badNestedPt == null) - return; - } - validErr = new TopologyValidationError( - TopologyValidationError.NESTED_SHELLS, - badNestedPt); - } - - /** - * This routine checks to see if a shell is properly contained in a hole. - * It assumes that the edges of the shell and hole do not - * properly intersect. - * - * @return null if the shell is properly contained, or - * a Coordinate which is not inside the hole if it is not - * - */ - private Coordinate checkShellInsideHole(LinearRing shell, LinearRing hole, GeometryGraph graph) - { - Coordinate[] shellPts = shell.getCoordinates(); - Coordinate[] holePts = hole.getCoordinates(); - // TODO: improve performance of this - by sorting pointlists for instance? - Coordinate shellPt = findPtNotNode(shellPts, hole, graph); - // if point is on shell but not hole, check that the shell is inside the hole - if (shellPt != null) { - boolean insideHole = CGAlgorithms.isPointInRing(shellPt, holePts); - if (! insideHole) { - return shellPt; - } - } - Coordinate holePt = findPtNotNode(holePts, shell, graph); - // if point is on hole but not shell, check that the hole is outside the shell - if (holePt != null) { - boolean insideShell = CGAlgorithms.isPointInRing(holePt, shellPts); - if (insideShell) { - return holePt; - } - return null; - } - Assert.shouldNeverReachHere("points in shell and hole appear to be equal"); - return null; - } - - private void checkConnectedInteriors(GeometryGraph graph) - { - ConnectedInteriorTester cit = new ConnectedInteriorTester(graph); - if (! cit.isInteriorsConnected()) - validErr = new TopologyValidationError( - TopologyValidationError.DISCONNECTED_INTERIOR, - cit.getCoordinate()); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java deleted file mode 100644 index 98cea53b16..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java +++ /dev/null @@ -1,116 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.index.quadtree.Quadtree; -import com.vividsolutions.jts.util.*; - -/** - * Tests whether any of a set of {@link LinearRing}s are - * nested inside another ring in the set, using a {@link Quadtree} - * index to speed up the comparisons. - * - * @version 1.7 - */ -public class QuadtreeNestedRingTester -{ - - private GeometryGraph graph; // used to find non-node vertices - private List rings = new ArrayList(); - private Envelope totalEnv = new Envelope(); - private Quadtree quadtree; - private Coordinate nestedPt; - - public QuadtreeNestedRingTester(GeometryGraph graph) - { - this.graph = graph; - } - - public Coordinate getNestedPoint() { return nestedPt; } - - public void add(LinearRing ring) - { - rings.add(ring); - totalEnv.expandToInclude(ring.getEnvelopeInternal()); - } - - public boolean isNonNested() - { - buildQuadtree(); - - for (int i = 0; i < rings.size(); i++) { - LinearRing innerRing = (LinearRing) rings.get(i); - Coordinate[] innerRingPts = innerRing.getCoordinates(); - - List results = quadtree.query(innerRing.getEnvelopeInternal()); -//System.out.println(results.size()); - for (int j = 0; j < results.size(); j++) { - LinearRing searchRing = (LinearRing) results.get(j); - Coordinate[] searchRingPts = searchRing.getCoordinates(); - - if (innerRing == searchRing) - continue; - - if (! innerRing.getEnvelopeInternal().intersects(searchRing.getEnvelopeInternal())) - continue; - - Coordinate innerRingPt = IsValidOp.findPtNotNode(innerRingPts, searchRing, graph); - Assert.isTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring"); - //Coordinate innerRingPt = innerRingPts[0]; - - boolean isInside = CGAlgorithms.isPointInRing(innerRingPt, searchRingPts); - if (isInside) { - nestedPt = innerRingPt; - return false; - } - } - } - return true; - } - - private void buildQuadtree() - { - quadtree = new Quadtree(); - - for (int i = 0; i < rings.size(); i++) { - LinearRing ring = (LinearRing) rings.get(i); - Envelope env = ring.getEnvelopeInternal(); - quadtree.insert(env, ring); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java deleted file mode 100644 index 875064924a..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java +++ /dev/null @@ -1,96 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import com.vividsolutions.jts.geom.*; - -/** - * Implements the appropriate checks for repeated points - * (consecutive identical coordinates) as defined in the - * JTS spec. - * - * @version 1.7 - */ -public class RepeatedPointTester { - - // save the repeated coord found (if any) - private Coordinate repeatedCoord; - - public RepeatedPointTester() { - } - - public Coordinate getCoordinate() { return repeatedCoord; } - - public boolean hasRepeatedPoint(Geometry g) - { - if (g.isEmpty()) return false; - if (g instanceof Point) return false; - else if (g instanceof MultiPoint) return false; - // LineString also handles LinearRings - else if (g instanceof LineString) return hasRepeatedPoint(((LineString) g).getCoordinates()); - else if (g instanceof Polygon) return hasRepeatedPoint((Polygon) g); - else if (g instanceof GeometryCollection) return hasRepeatedPoint((GeometryCollection) g); - else throw new UnsupportedOperationException(g.getClass().getName()); - } - - public boolean hasRepeatedPoint(Coordinate[] coord) - { - for (int i = 1; i < coord.length; i++) { - if (coord[i - 1].equals(coord[i]) ) { - repeatedCoord = coord[i]; - return true; - } - } - return false; - } - private boolean hasRepeatedPoint(Polygon p) - { - if (hasRepeatedPoint(p.getExteriorRing().getCoordinates())) return true; - for (int i = 0; i < p.getNumInteriorRing(); i++) { - if (hasRepeatedPoint(p.getInteriorRingN(i).getCoordinates())) return true; - } - return false; - } - private boolean hasRepeatedPoint(GeometryCollection gc) - { - for (int i = 0; i < gc.getNumGeometries(); i++) { - Geometry g = gc.getGeometryN(i); - if (hasRepeatedPoint(g)) return true; - } - return false; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java deleted file mode 100644 index 023fc33a86..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java +++ /dev/null @@ -1,98 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.util.*; - -/** - * Tests whether any of a set of {@link LinearRing}s are - * nested inside another ring in the set, using a simple O(n^2) - * comparison. - * - * @version 1.7 - */ -public class SimpleNestedRingTester -{ - - private GeometryGraph graph; // used to find non-node vertices - private List rings = new ArrayList(); - private Coordinate nestedPt; - - public SimpleNestedRingTester(GeometryGraph graph) - { - this.graph = graph; - } - - public void add(LinearRing ring) - { - rings.add(ring); - } - - public Coordinate getNestedPoint() { return nestedPt; } - - public boolean isNonNested() - { - for (int i = 0; i < rings.size(); i++) { - LinearRing innerRing = (LinearRing) rings.get(i); - Coordinate[] innerRingPts = innerRing.getCoordinates(); - - for (int j = 0; j < rings.size(); j++) { - LinearRing searchRing = (LinearRing) rings.get(j); - Coordinate[] searchRingPts = searchRing.getCoordinates(); - - if (innerRing == searchRing) - continue; - - if (! innerRing.getEnvelopeInternal().intersects(searchRing.getEnvelopeInternal())) - continue; - - Coordinate innerRingPt = IsValidOp.findPtNotNode(innerRingPts, searchRing, graph); - Assert.isTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring"); - //Coordinate innerRingPt = innerRingPts[0]; - - boolean isInside = CGAlgorithms.isPointInRing(innerRingPt, searchRingPts); - if (isInside) { - nestedPt = innerRingPt; - return false; - } - } - } - return true; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java b/src/main/java/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java deleted file mode 100644 index d888cb044e..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java +++ /dev/null @@ -1,129 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geomgraph.*; -import com.vividsolutions.jts.index.sweepline.*; -import com.vividsolutions.jts.util.*; - -/** - * Tests whether any of a set of {@link LinearRing}s are - * nested inside another ring in the set, using a {@link SweepLineIndex} - * index to speed up the comparisons. - * - * @version 1.7 - */ -public class SweeplineNestedRingTester -{ - - private GeometryGraph graph; // used to find non-node vertices - private List rings = new ArrayList(); - //private Envelope totalEnv = new Envelope(); - private SweepLineIndex sweepLine; - private Coordinate nestedPt = null; - - public SweeplineNestedRingTester(GeometryGraph graph) - { - this.graph = graph; - } - - public Coordinate getNestedPoint() { return nestedPt; } - - public void add(LinearRing ring) - { - rings.add(ring); - } - - public boolean isNonNested() - { - buildIndex(); - - OverlapAction action = new OverlapAction(); - - sweepLine.computeOverlaps(action); - return action.isNonNested; - } - - private void buildIndex() - { - sweepLine = new SweepLineIndex(); - - for (int i = 0; i < rings.size(); i++) { - LinearRing ring = (LinearRing) rings.get(i); - Envelope env = ring.getEnvelopeInternal(); - SweepLineInterval sweepInt = new SweepLineInterval(env.getMinX(), env.getMaxX(), ring); - sweepLine.add(sweepInt); - } - } - - private boolean isInside(LinearRing innerRing, LinearRing searchRing) - { - Coordinate[] innerRingPts = innerRing.getCoordinates(); - Coordinate[] searchRingPts = searchRing.getCoordinates(); - - if (! innerRing.getEnvelopeInternal().intersects(searchRing.getEnvelopeInternal())) - return false; - - Coordinate innerRingPt = IsValidOp.findPtNotNode(innerRingPts, searchRing, graph); - Assert.isTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring"); - - boolean isInside = CGAlgorithms.isPointInRing(innerRingPt, searchRingPts); - if (isInside) { - nestedPt = innerRingPt; - return true; - } - return false; - } - - - class OverlapAction - implements SweepLineOverlapAction - { - boolean isNonNested = true; - - public void overlap(SweepLineInterval s0, SweepLineInterval s1) - { - LinearRing innerRing = (LinearRing) s0.getItem(); - LinearRing searchRing = (LinearRing) s1.getItem(); - if (innerRing == searchRing) return; - - if (isInside(innerRing, searchRing)) - isNonNested = false; - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/operation/valid/TopologyValidationError.java b/src/main/java/com/vividsolutions/jts/operation/valid/TopologyValidationError.java deleted file mode 100644 index 78f8995cd7..0000000000 --- a/src/main/java/com/vividsolutions/jts/operation/valid/TopologyValidationError.java +++ /dev/null @@ -1,193 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.operation.valid; - -import com.vividsolutions.jts.geom.*; - -/** - * Contains information about the nature and location of a {@link Geometry} - * validation error - * - * @version 1.7 - */ -public class TopologyValidationError { - - /** - * Not used - * @deprecated - */ - public static final int ERROR = 0; - /** - * No longer used - repeated points are considered valid as per the SFS - * @deprecated - */ - public static final int REPEATED_POINT = 1; - - /** - * Indicates that a hole of a polygon lies partially or completely in the exterior of the shell - */ - public static final int HOLE_OUTSIDE_SHELL = 2; - - /** - * Indicates that a hole lies in the interior of another hole in the same polygon - */ - public static final int NESTED_HOLES = 3; - - /** - * Indicates that the interior of a polygon is disjoint - * (often caused by set of contiguous holes splitting the polygon into two parts) - */ - public static final int DISCONNECTED_INTERIOR = 4; - - /** - * Indicates that two rings of a polygonal geometry intersect - */ - public static final int SELF_INTERSECTION = 5; - - /** - * Indicates that a ring self-intersects - */ - public static final int RING_SELF_INTERSECTION = 6; - - /** - * Indicates that a polygon component of a MultiPolygon lies inside another polygonal component - */ - public static final int NESTED_SHELLS = 7; - - /** - * Indicates that a polygonal geometry contains two rings which are identical - */ - public static final int DUPLICATE_RINGS = 8; - - /** - * Indicates that either - *

                        - *
                      • a LineString contains a single point - *
                      • a LinearRing contains 2 or 3 points - *
                      - */ - public static final int TOO_FEW_POINTS = 9; - - /** - * Indicates that the X or Y ordinate of - * a Coordinate is not a valid numeric value (e.g. {@link Double#NaN} ) - */ - public static final int INVALID_COORDINATE = 10; - - /** - * Indicates that a ring is not correctly closed - * (the first and the last coordinate are different) - */ - public static final int RING_NOT_CLOSED = 11; - - /** - * Messages corresponding to error codes - */ - public static final String[] errMsg = { - "Topology Validation Error", - "Repeated Point", - "Hole lies outside shell", - "Holes are nested", - "Interior is disconnected", - "Self-intersection", - "Ring Self-intersection", - "Nested shells", - "Duplicate Rings", - "Too few distinct points in geometry component", - "Invalid Coordinate", - "Ring is not closed" - }; - - private int errorType; - private Coordinate pt; - - /** - * Creates a validation error with the given type and location - * - * @param errorType the type of the error - * @param pt the location of the error - */ - public TopologyValidationError(int errorType, Coordinate pt) - { - this.errorType = errorType; - if (pt != null) - this.pt = (Coordinate) pt.clone(); - } - - /** - * Creates a validation error of the given type with a null location - * - * @param errorType the type of the error - * - */ - public TopologyValidationError(int errorType) - { - this(errorType, null); - } - - /** - * Returns the location of this error (on the {@link Geometry} containing the error). - * - * @return a {@link Coordinate} on the input geometry - */ - public Coordinate getCoordinate() { return pt; } - - /** - * Gets the type of this error. - * - * @return the error type - */ - public int getErrorType() { return errorType; } - - /** - * Gets an error message describing this error. - * The error message does not describe the location of the error. - * - * @return the error message - */ - public String getMessage() { return errMsg[errorType]; } - - /** - * Gets a message describing the type and location of this error. - * @return the error message - */ - public String toString() - { - String locStr = ""; - if (pt != null) - locStr = " at or near point " + pt; - return getMessage() + locStr; - } -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdge.java b/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdge.java deleted file mode 100644 index 72f0ca0df4..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdge.java +++ /dev/null @@ -1,230 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.planargraph; - -import java.util.*; -import java.io.PrintStream; -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geomgraph.Quadrant; - -/** - * Represents a directed edge in a {@link PlanarGraph}. A DirectedEdge may or - * may not have a reference to a parent {@link Edge} (some applications of - * planar graphs may not require explicit Edge objects to be created). Usually - * a client using a PlanarGraph will subclass DirectedEdge - * to add its own application-specific data and methods. - * - * @version 1.7 - */ -public class DirectedEdge - extends GraphComponent - implements Comparable -{ - /** - * Returns a List containing the parent Edge (possibly null) for each of the given - * DirectedEdges. - */ - public static List toEdges(Collection dirEdges) - { - List edges = new ArrayList(); - for (Iterator i = dirEdges.iterator(); i.hasNext(); ) { - edges.add( ((DirectedEdge) i.next()).parentEdge); - } - return edges; - } - - protected Edge parentEdge; - protected Node from; - protected Node to; - protected Coordinate p0, p1; - protected DirectedEdge sym = null; // optional - protected boolean edgeDirection; - protected int quadrant; - protected double angle; - - /** - * Constructs a DirectedEdge connecting the from node to the - * to node. - * - * @param directionPt - * specifies this DirectedEdge's direction vector - * (determined by the vector from the from node - * to directionPt) - * @param edgeDirection - * whether this DirectedEdge's direction is the same as or - * opposite to that of the parent Edge (if any) - */ - public DirectedEdge(Node from, Node to, Coordinate directionPt, boolean edgeDirection) - { - this.from = from; - this.to = to; - this.edgeDirection = edgeDirection; - p0 = from.getCoordinate(); - p1 = directionPt; - double dx = p1.x - p0.x; - double dy = p1.y - p0.y; - quadrant = Quadrant.quadrant(dx, dy); - angle = Math.atan2(dy, dx); - //Assert.isTrue(! (dx == 0 && dy == 0), "EdgeEnd with identical endpoints found"); - } - - /** - * Returns this DirectedEdge's parent Edge, or null if it has none. - */ - public Edge getEdge() { return parentEdge; } - /** - * Associates this DirectedEdge with an Edge (possibly null, indicating no associated - * Edge). - */ - public void setEdge(Edge parentEdge) { this.parentEdge = parentEdge; } - /** - * Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's - * orientation lies. - */ - public int getQuadrant() { return quadrant; } - /** - * Returns a point to which an imaginary line is drawn from the from-node to - * specify this DirectedEdge's orientation. - */ - public Coordinate getDirectionPt() { return p1; } - /** - * Returns whether the direction of the parent Edge (if any) is the same as that - * of this Directed Edge. - */ - public boolean getEdgeDirection() { return edgeDirection; } - /** - * Returns the node from which this DirectedEdge leaves. - */ - public Node getFromNode() { return from; } - /** - * Returns the node to which this DirectedEdge goes. - */ - public Node getToNode() { return to; } - /** - * Returns the coordinate of the from-node. - */ - public Coordinate getCoordinate() { return from.getCoordinate(); } - /** - * Returns the angle that the start of this DirectedEdge makes with the - * positive x-axis, in radians. - */ - public double getAngle() { return angle; } - /** - * Returns the symmetric DirectedEdge -- the other DirectedEdge associated with - * this DirectedEdge's parent Edge. - */ - public DirectedEdge getSym() { return sym; } - /** - * Sets this DirectedEdge's symmetric DirectedEdge, which runs in the opposite - * direction. - */ - public void setSym(DirectedEdge sym) { this.sym = sym; } - - /** - * Removes this directed edge from its containing graph. - */ - void remove() { - this.sym = null; - this.parentEdge = null; - } - - /** - * Tests whether this directed edge has been removed from its containing graph - * - * @return true if this directed edge is removed - */ - public boolean isRemoved() - { - return parentEdge == null; - } - - /** - * Returns 1 if this DirectedEdge has a greater angle with the - * positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. - *

                      - * Using the obvious algorithm of simply computing the angle is not robust, - * since the angle calculation is susceptible to roundoff. A robust algorithm - * is: - *

                        - *
                      • first compare the quadrants. If the quadrants are different, it it - * trivial to determine which vector is "greater". - *
                      • if the vectors lie in the same quadrant, the robust - * {@link CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate)} - * function can be used to decide the relative orientation of the vectors. - *
                      - */ - public int compareTo(Object obj) - { - DirectedEdge de = (DirectedEdge) obj; - return compareDirection(de); - } - - /** - * Returns 1 if this DirectedEdge has a greater angle with the - * positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. - *

                      - * Using the obvious algorithm of simply computing the angle is not robust, - * since the angle calculation is susceptible to roundoff. A robust algorithm - * is: - *

                        - *
                      • first compare the quadrants. If the quadrants are different, it it - * trivial to determine which vector is "greater". - *
                      • if the vectors lie in the same quadrant, the robust - * {@link CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate)} - * function can be used to decide the relative orientation of the vectors. - *
                      - */ - public int compareDirection(DirectedEdge e) - { - // if the rays are in different quadrants, determining the ordering is trivial - if (quadrant > e.quadrant) return 1; - if (quadrant < e.quadrant) return -1; - // vectors are in the same quadrant - check relative orientation of direction vectors - // this is > e if it is CCW of e - return CGAlgorithms.computeOrientation(e.p0, e.p1, p1); - } - - /** - * Prints a detailed string representation of this DirectedEdge to the given PrintStream. - */ - public void print(PrintStream out) - { - String className = getClass().getName(); - int lastDotPos = className.lastIndexOf('.'); - String name = className.substring(lastDotPos + 1); - out.print(" " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java b/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java deleted file mode 100644 index c79e966806..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java +++ /dev/null @@ -1,180 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - - -package com.vividsolutions.jts.planargraph; - -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A sorted collection of {@link DirectedEdge}s which leave a {@link Node} - * in a {@link PlanarGraph}. - * - * @version 1.7 - */ -public class DirectedEdgeStar -{ - - /** - * The underlying list of outgoing DirectedEdges - */ - protected List outEdges = new ArrayList(); - private boolean sorted = false; - - /** - * Constructs a DirectedEdgeStar with no edges. - */ - public DirectedEdgeStar() { - } - /** - * Adds a new member to this DirectedEdgeStar. - */ - public void add(DirectedEdge de) - { - outEdges.add(de); - sorted = false; - } - /** - * Drops a member of this DirectedEdgeStar. - */ - public void remove(DirectedEdge de) - { - outEdges.remove(de); - } - /** - * Returns an Iterator over the DirectedEdges, in ascending order by angle with the positive x-axis. - */ - public Iterator iterator() - { - sortEdges(); - return outEdges.iterator(); - } - - /** - * Returns the number of edges around the Node associated with this DirectedEdgeStar. - */ - public int getDegree() { return outEdges.size(); } - - /** - * Returns the coordinate for the node at wich this star is based - */ - public Coordinate getCoordinate() - { - Iterator it = iterator(); - if (! it.hasNext()) return null; - DirectedEdge e = (DirectedEdge) it.next(); - return e.getCoordinate(); - } - - /** - * Returns the DirectedEdges, in ascending order by angle with the positive x-axis. - */ - public List getEdges() - { - sortEdges(); - return outEdges; - } - - private void sortEdges() - { - if (! sorted) { - Collections.sort(outEdges); - sorted = true; - } - } - /** - * Returns the zero-based index of the given Edge, after sorting in ascending order - * by angle with the positive x-axis. - */ - public int getIndex(Edge edge) - { - sortEdges(); - for (int i = 0; i < outEdges.size(); i++) { - DirectedEdge de = (DirectedEdge) outEdges.get(i); - if (de.getEdge() == edge) - return i; - } - return -1; - } - /** - * Returns the zero-based index of the given DirectedEdge, after sorting in ascending order - * by angle with the positive x-axis. - */ - public int getIndex(DirectedEdge dirEdge) - { - sortEdges(); - for (int i = 0; i < outEdges.size(); i++) { - DirectedEdge de = (DirectedEdge) outEdges.get(i); - if (de == dirEdge) - return i; - } - return -1; - } - /** - * Returns value of i modulo the number of edges in this DirectedEdgeStar - * (i.e. the remainder when i is divided by the number of edges) - * - * @param i an integer (positive, negative or zero) - */ - public int getIndex(int i) - { - int modi = i % outEdges.size(); - //I don't think modi can be 0 (assuming i is positive) [Jon Aquino 10/28/2003] - if (modi < 0) modi += outEdges.size(); - return modi; - } - - /** - * Returns the {@link DirectedEdge} on the left-hand (CCW) - * side of the given {@link DirectedEdge} - * (which must be a member of this DirectedEdgeStar). - */ - public DirectedEdge getNextEdge(DirectedEdge dirEdge) - { - int i = getIndex(dirEdge); - return (DirectedEdge) outEdges.get(getIndex(i + 1)); - } - - /** - * Returns the {@link DirectedEdge} on the right-hand (CW) - * side of the given {@link DirectedEdge} - * (which must be a member of this DirectedEdgeStar). - */ - public DirectedEdge getNextCWEdge(DirectedEdge dirEdge) - { - int i = getIndex(dirEdge); - return (DirectedEdge) outEdges.get(getIndex(i - 1)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/Edge.java b/src/main/java/com/vividsolutions/jts/planargraph/Edge.java deleted file mode 100644 index c30d916aa4..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/Edge.java +++ /dev/null @@ -1,141 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.planargraph; - -/** - * Represents an undirected edge of a {@link PlanarGraph}. An undirected edge - * in fact simply acts as a central point of reference for two opposite - * {@link DirectedEdge}s. - *

                      - * Usually a client using a PlanarGraph will subclass Edge - * to add its own application-specific data and methods. - * - * @version 1.7 - */ -public class Edge - extends GraphComponent -{ - - /** - * The two DirectedEdges associated with this Edge. - * Index 0 is forward, 1 is reverse. - */ - protected DirectedEdge[] dirEdge; - - /** - * Constructs an Edge whose DirectedEdges are not yet set. Be sure to call - * {@link #setDirectedEdges(DirectedEdge, DirectedEdge)} - */ - public Edge() - { - } - - /** - * Constructs an Edge initialized with the given DirectedEdges, and for each - * DirectedEdge: sets the Edge, sets the symmetric DirectedEdge, and adds - * this Edge to its from-Node. - */ - public Edge(DirectedEdge de0, DirectedEdge de1) - { - setDirectedEdges(de0, de1); - } - - /** - * Initializes this Edge's two DirectedEdges, and for each DirectedEdge: sets the - * Edge, sets the symmetric DirectedEdge, and adds this Edge to its from-Node. - */ - public void setDirectedEdges(DirectedEdge de0, DirectedEdge de1) - { - dirEdge = new DirectedEdge[] { de0, de1 }; - de0.setEdge(this); - de1.setEdge(this); - de0.setSym(de1); - de1.setSym(de0); - de0.getFromNode().addOutEdge(de0); - de1.getFromNode().addOutEdge(de1); - } - - /** - * Returns one of the DirectedEdges associated with this Edge. - * @param i 0 or 1. 0 returns the forward directed edge, 1 returns the reverse - */ - public DirectedEdge getDirEdge(int i) - { - return dirEdge[i]; - } - - /** - * Returns the {@link DirectedEdge} that starts from the given node, or null if the - * node is not one of the two nodes associated with this Edge. - */ - public DirectedEdge getDirEdge(Node fromNode) - { - if (dirEdge[0].getFromNode() == fromNode) return dirEdge[0]; - if (dirEdge[1].getFromNode() == fromNode) return dirEdge[1]; - // node not found - // possibly should throw an exception here? - return null; - } - - /** - * If node is one of the two nodes associated with this Edge, - * returns the other node; otherwise returns null. - */ - public Node getOppositeNode(Node node) - { - if (dirEdge[0].getFromNode() == node) return dirEdge[0].getToNode(); - if (dirEdge[1].getFromNode() == node) return dirEdge[1].getToNode(); - // node not found - // possibly should throw an exception here? - return null; - } - - /** - * Removes this edge from its containing graph. - */ - void remove() { - this.dirEdge = null; - } - - /** - * Tests whether this edge has been removed from its containing graph - * - * @return true if this edge is removed - */ - public boolean isRemoved() - { - return dirEdge == null; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/GraphComponent.java b/src/main/java/com/vividsolutions/jts/planargraph/GraphComponent.java deleted file mode 100644 index 977c66477b..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/GraphComponent.java +++ /dev/null @@ -1,171 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.planargraph; - -import java.util.Iterator; - -/** - * The base class for all graph component classes. - * Maintains flags of use in generic graph algorithms. - * Provides two flags: - *

                        - *
                      • marked - typically this is used to indicate a state that persists - * for the course of the graph's lifetime. For instance, it can be - * used to indicate that a component has been logically deleted from the graph. - *
                      • visited - this is used to indicate that a component has been processed - * or visited by an single graph algorithm. For instance, a breadth-first traversal of the - * graph might use this to indicate that a node has already been traversed. - * The visited flag may be set and cleared many times during the lifetime of a graph. - * - *

                        - * Graph components support storing user context data. This will typically be - * used by client algorithms which use planar graphs. - * - * @version 1.7 - */ -public abstract class GraphComponent -{ - /** - * Sets the Visited state for all {@link GraphComponent}s in an {@link Iterator} - * - * @param i the Iterator to scan - * @param visited the state to set the visited flag to - */ - public static void setVisited(Iterator i, boolean visited) - { - while (i.hasNext()) { - GraphComponent comp = (GraphComponent) i.next(); - comp.setVisited(visited); - } - } - - /** - * Sets the Marked state for all {@link GraphComponent}s in an {@link Iterator} - * - * @param i the Iterator to scan - * @param marked the state to set the Marked flag to - */ - public static void setMarked(Iterator i, boolean marked) - { - while (i.hasNext()) { - GraphComponent comp = (GraphComponent) i.next(); - comp.setMarked(marked); - } - } - - /** - * Finds the first {@link GraphComponent} in a {@link Iterator} set - * which has the specified visited state. - * - * @param i an Iterator of GraphComponents - * @param visitedState the visited state to test - * @return the first component found, or null if none found - */ - public static GraphComponent getComponentWithVisitedState(Iterator i, boolean visitedState) - { - while (i.hasNext()) { - GraphComponent comp = (GraphComponent) i.next(); - if (comp.isVisited() == visitedState) - return comp; - } - return null; - } - - protected boolean isMarked = false; - protected boolean isVisited = false; - private Object data; - - public GraphComponent() { - } - - /** - * Tests if a component has been visited during the course of a graph algorithm - * @return true if the component has been visited - */ - public boolean isVisited() { return isVisited; } - - /** - * Sets the visited flag for this component. - * @param isVisited the desired value of the visited flag - */ - public void setVisited(boolean isVisited) { this.isVisited = isVisited; } - - /** - * Tests if a component has been marked at some point during the processing - * involving this graph. - * @return true if the component has been marked - */ - public boolean isMarked() { return isMarked; } - - /** - * Sets the marked flag for this component. - * @param isMarked the desired value of the marked flag - */ - public void setMarked(boolean isMarked) { this.isMarked = isMarked; } - - /** - * Sets the user-defined data for this component. - * - * @param data an Object containing user-defined data - */ - public void setContext(Object data) { this.data = data; } - - /** - * Gets the user-defined data for this component. - * - * @return the user-defined data - */ - public Object getContext() { return data; } - - /** - * Sets the user-defined data for this component. - * - * @param data an Object containing user-defined data - */ - public void setData(Object data) { this.data = data; } - - /** - * Gets the user-defined data for this component. - * - * @return the user-defined data - */ - public Object getData() { return data; } - - /** - * Tests whether this component has been removed from its containing graph - * - * @return true if this component is removed - */ - public abstract boolean isRemoved(); -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/Node.java b/src/main/java/com/vividsolutions/jts/planargraph/Node.java deleted file mode 100644 index 368803f2e0..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/Node.java +++ /dev/null @@ -1,145 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - - -package com.vividsolutions.jts.planargraph; - -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A node in a {@link PlanarGraph}is a location where 0 or more {@link Edge}s - * meet. A node is connected to each of its incident Edges via an outgoing - * DirectedEdge. Some clients using a PlanarGraph may want to - * subclass Node to add their own application-specific - * data and methods. - * - * @version 1.7 - */ -public class Node - extends GraphComponent -{ - /** - * Returns all Edges that connect the two nodes (which are assumed to be different). - */ - public static Collection getEdgesBetween(Node node0, Node node1) - { - List edges0 = DirectedEdge.toEdges(node0.getOutEdges().getEdges()); - Set commonEdges = new HashSet(edges0); - List edges1 = DirectedEdge.toEdges(node1.getOutEdges().getEdges()); - commonEdges.retainAll(edges1); - return commonEdges; - } - - /** The location of this Node */ - protected Coordinate pt; - - /** The collection of DirectedEdges that leave this Node */ - protected DirectedEdgeStar deStar; - - /** - * Constructs a Node with the given location. - */ - public Node(Coordinate pt) - { - this(pt, new DirectedEdgeStar()); - } - - /** - * Constructs a Node with the given location and collection of outgoing DirectedEdges. - */ - public Node(Coordinate pt, DirectedEdgeStar deStar) - { - this.pt = pt; - this.deStar = deStar; - } - - /** - * Returns the location of this Node. - */ - public Coordinate getCoordinate() { return pt; } - - /** - * Adds an outgoing DirectedEdge to this Node. - */ - public void addOutEdge(DirectedEdge de) - { - deStar.add(de); - } - - /** - * Returns the collection of DirectedEdges that leave this Node. - */ - public DirectedEdgeStar getOutEdges() { return deStar; } - /** - * Returns the number of edges around this Node. - */ - public int getDegree() { return deStar.getDegree(); } - /** - * Returns the zero-based index of the given Edge, after sorting in ascending order - * by angle with the positive x-axis. - */ - public int getIndex(Edge edge) - { - return deStar.getIndex(edge); - } - - /** - * Removes a {@link DirectedEdge} incident on this node. - * Does not change the state of the directed edge. - */ - public void remove(DirectedEdge de) - { - deStar.remove(de); - } - - /** - * Removes this node from its containing graph. - */ - void remove() { - pt = null; - } - - - /** - * Tests whether this node has been removed from its containing graph - * - * @return true if this node is removed - */ - public boolean isRemoved() - { - return pt == null; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/NodeMap.java b/src/main/java/com/vividsolutions/jts/planargraph/NodeMap.java deleted file mode 100644 index e465699d21..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/NodeMap.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.planargraph; - - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A map of {@link Node}s, indexed by the coordinate of the node. - * - * @version 1.7 - */ -public class NodeMap - -{ - - private Map nodeMap = new TreeMap(); - - /** - * Constructs a NodeMap without any Nodes. - */ - public NodeMap() { - } - - /** - * Adds a node to the map, replacing any that is already at that location. - * @return the added node - */ - public Node add(Node n) - { - nodeMap.put(n.getCoordinate(), n); - return n; - } - - /** - * Removes the Node at the given location, and returns it (or null if no Node was there). - */ - public Node remove(Coordinate pt) - { - return (Node) nodeMap.remove(pt); - } - - /** - * Returns the Node at the given location, or null if no Node was there. - */ - public Node find(Coordinate coord) { return (Node) nodeMap.get(coord); } - - /** - * Returns an Iterator over the Nodes in this NodeMap, sorted in ascending order - * by angle with the positive x-axis. - */ - public Iterator iterator() - { - return nodeMap.values().iterator(); - } - /** - * Returns the Nodes in this NodeMap, sorted in ascending order - * by angle with the positive x-axis. - */ - public Collection values() - { - return nodeMap.values(); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/PlanarGraph.java b/src/main/java/com/vividsolutions/jts/planargraph/PlanarGraph.java deleted file mode 100644 index 810819cb91..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/PlanarGraph.java +++ /dev/null @@ -1,235 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.planargraph; - -import java.util.*; -import com.vividsolutions.jts.geom.Coordinate; - -/** - * Represents a directed graph which is embeddable in a planar surface. - *

                        - * This class and the other classes in this package serve as a framework for - * building planar graphs for specific algorithms. This class must be - * subclassed to expose appropriate methods to construct the graph. This allows - * controlling the types of graph components ({@link DirectedEdge}s, - * {@link Edge}s and {@link Node}s) which can be added to the graph. An - * application which uses the graph framework will almost always provide - * subclasses for one or more graph components, which hold application-specific - * data and graph algorithms. - * - * @version 1.7 - */ -public abstract class PlanarGraph -{ - protected Set edges = new HashSet(); - protected Set dirEdges = new HashSet(); - protected NodeMap nodeMap = new NodeMap(); - - /** - * Constructs a empty graph. - */ - public PlanarGraph() - { - } - - /** - * Returns the {@link Node} at the given location, - * or null if no {@link Node} was there. - * - * @param pt the location to query - * @return the node found - * or null if this graph contains no node at the location - */ - public Node findNode(Coordinate pt) - { - return (Node) nodeMap.find(pt); - } - - /** - * Adds a node to the map, replacing any that is already at that location. - * Only subclasses can add Nodes, to ensure Nodes are of the right type. - * - * @param node the node to add - */ - protected void add(Node node) - { - nodeMap.add(node); - } - - /** - * Adds the Edge and its DirectedEdges with this PlanarGraph. - * Assumes that the Edge has already been created with its associated DirectEdges. - * Only subclasses can add Edges, to ensure the edges added are of the right class. - */ - protected void add(Edge edge) - { - edges.add(edge); - add(edge.getDirEdge(0)); - add(edge.getDirEdge(1)); - } - - /** - * Adds the Edge to this PlanarGraph; only subclasses can add DirectedEdges, - * to ensure the edges added are of the right class. - */ - protected void add(DirectedEdge dirEdge) - { - dirEdges.add(dirEdge); - } - /** - * Returns an Iterator over the Nodes in this PlanarGraph. - */ - public Iterator nodeIterator() { return nodeMap.iterator(); } - /** - * Returns the Nodes in this PlanarGraph. - */ - - /** - * Tests whether this graph contains the given {@link Edge} - * - * @param e the edge to query - * @return true if the graph contains the edge - */ - public boolean contains(Edge e) - { - return edges.contains(e); - } - - /** - * Tests whether this graph contains the given {@link DirectedEdge} - * - * @param de the directed edge to query - * @return true if the graph contains the directed edge - */ - public boolean contains(DirectedEdge de) - { - return dirEdges.contains(de); - } - - public Collection getNodes() { return nodeMap.values(); } - - /** - * Returns an Iterator over the DirectedEdges in this PlanarGraph, in the order in which they - * were added. - * - * @see #add(Edge) - * @see #add(DirectedEdge) - */ - public Iterator dirEdgeIterator() { return dirEdges.iterator(); } - /** - * Returns an Iterator over the Edges in this PlanarGraph, in the order in which they - * were added. - * - * @see #add(Edge) - */ - public Iterator edgeIterator() { return edges.iterator(); } - - /** - * Returns the Edges that have been added to this PlanarGraph - * @see #add(Edge) - */ - public Collection getEdges() { return edges; } - - /** - * Removes an {@link Edge} and its associated {@link DirectedEdge}s - * from their from-Nodes and from the graph. - * Note: This method does not remove the {@link Node}s associated - * with the {@link Edge}, even if the removal of the {@link Edge} - * reduces the degree of a {@link Node} to zero. - */ - public void remove(Edge edge) - { - remove(edge.getDirEdge(0)); - remove(edge.getDirEdge(1)); - edges.remove(edge); - edge.remove(); - } - - /** - * Removes a {@link DirectedEdge} from its from-{@link Node} and from this graph. - * This method does not remove the {@link Node}s associated with the DirectedEdge, - * even if the removal of the DirectedEdge reduces the degree of a Node to zero. - */ - public void remove(DirectedEdge de) - { - DirectedEdge sym = de.getSym(); - if (sym != null) sym.setSym(null); - - de.getFromNode().remove(de); - de.remove(); - dirEdges.remove(de); - } - - /** - * Removes a node from the graph, along with any associated DirectedEdges and - * Edges. - */ - public void remove(Node node) - { - // unhook all directed edges - List outEdges = node.getOutEdges().getEdges(); - for (Iterator i = outEdges.iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - DirectedEdge sym = de.getSym(); - // remove the diredge that points to this node - if (sym != null) remove(sym); - // remove this diredge from the graph collection - dirEdges.remove(de); - - Edge edge = de.getEdge(); - if (edge != null) { - edges.remove(edge); - } - - } - // remove the node from the graph - nodeMap.remove(node.getCoordinate()); - node.remove(); - } - - /** - * Returns all Nodes with the given number of Edges around it. - */ - public List findNodesOfDegree(int degree) - { - List nodesFound = new ArrayList(); - for (Iterator i = nodeIterator(); i.hasNext(); ) { - Node node = (Node) i.next(); - if (node.getDegree() == degree) - nodesFound.add(node); - } - return nodesFound; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/Subgraph.java b/src/main/java/com/vividsolutions/jts/planargraph/Subgraph.java deleted file mode 100644 index 34b3a0f902..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/Subgraph.java +++ /dev/null @@ -1,124 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.planargraph; - -import java.util.*; - -/** - * A subgraph of a {@link PlanarGraph}. - * A subgraph may contain any subset of {@link Edge}s - * from the parent graph. - * It will also automatically contain all {@link DirectedEdge}s - * and {@link Node}s associated with those edges. - * No new objects are created when edges are added - - * all associated components must already exist in the parent graph. - */ -public class Subgraph -{ - protected PlanarGraph parentGraph; - protected Set edges = new HashSet(); - protected List dirEdges = new ArrayList(); - protected NodeMap nodeMap = new NodeMap(); - - /** - * Creates a new subgraph of the given {@link PlanarGraph} - * - * @param parentGraph the parent graph - */ - public Subgraph(PlanarGraph parentGraph) { - this.parentGraph = parentGraph; - } - - /** - * Gets the {@link PlanarGraph} which this subgraph - * is part of. - * - * @return the parent PlanarGraph - */ - public PlanarGraph getParent() - { - return parentGraph; - } - /** - * Adds an {@link Edge} to the subgraph. - * The associated {@link DirectedEdge}s and {@link Node}s - * are also added. - * - * @param e the edge to add - */ - public void add(Edge e) - { - if (edges.contains(e)) return; - - edges.add(e); - dirEdges.add(e.getDirEdge(0)); - dirEdges.add(e.getDirEdge(1)); - nodeMap.add(e.getDirEdge(0).getFromNode()); - nodeMap.add(e.getDirEdge(1).getFromNode()); - } - - /** - * Returns an {@link Iterator} over the {@link DirectedEdge}s in this graph, - * in the order in which they were added. - * - * @return an iterator over the directed edges - * - * @see #add(Edge) - */ - public Iterator dirEdgeIterator() { return dirEdges.iterator(); } - - /** - * Returns an {@link Iterator} over the {@link Edge}s in this graph, - * in the order in which they were added. - * - * @return an iterator over the edges - * - * @see #add(Edge) - */ - public Iterator edgeIterator() { return edges.iterator(); } - - /** - * Returns an {@link Iterator} over the {@link Node}s in this graph. - * @return an iterator over the nodes - */ - public Iterator nodeIterator() { return nodeMap.iterator(); } - - /** - * Tests whether an {@link Edge} is contained in this subgraph - * @param e the edge to test - * @return true if the edge is contained in this subgraph - */ - public boolean contains(Edge e) { return edges.contains(e); } - -} diff --git a/src/main/java/com/vividsolutions/jts/planargraph/algorithm/ConnectedSubgraphFinder.java b/src/main/java/com/vividsolutions/jts/planargraph/algorithm/ConnectedSubgraphFinder.java deleted file mode 100644 index 3b4b966470..0000000000 --- a/src/main/java/com/vividsolutions/jts/planargraph/algorithm/ConnectedSubgraphFinder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.planargraph.algorithm; - -import java.util.*; -import com.vividsolutions.jts.planargraph.*; - -/** - * Finds all connected {@link Subgraph}s of a {@link PlanarGraph}. - *

                        - * Note: uses the isVisited flag on the nodes. - */ -public class ConnectedSubgraphFinder -{ - - private PlanarGraph graph; - - public ConnectedSubgraphFinder(PlanarGraph graph) { - this.graph = graph; - } - - public List getConnectedSubgraphs() - { - List subgraphs = new ArrayList(); - - GraphComponent.setVisited(graph.nodeIterator(), false); - for (Iterator i = graph.edgeIterator(); i.hasNext(); ) { - Edge e = (Edge) i.next(); - Node node = e.getDirEdge(0).getFromNode(); - if (! node.isVisited()) { - subgraphs.add(findSubgraph(node)); - } - } - return subgraphs; - } - - private Subgraph findSubgraph(Node node) - { - Subgraph subgraph = new Subgraph(graph); - addReachable(node, subgraph); - return subgraph; - } - - /** - * Adds all nodes and edges reachable from this node to the subgraph. - * Uses an explicit stack to avoid a large depth of recursion. - * - * @param node a node known to be in the subgraph - */ - private void addReachable(Node startNode, Subgraph subgraph) - { - Stack nodeStack = new Stack(); - nodeStack.add(startNode); - while (! nodeStack.empty()) { - Node node = (Node) nodeStack.pop(); - addEdges(node, nodeStack, subgraph); - } - } - - /** - * Adds the argument node and all its out edges to the subgraph. - * @param node the node to add - * @param nodeStack the current set of nodes being traversed - */ - private void addEdges(Node node, Stack nodeStack, Subgraph subgraph) - { - node.setVisited(true); - for (Iterator i = ((DirectedEdgeStar) node.getOutEdges()).iterator(); i.hasNext(); ) { - DirectedEdge de = (DirectedEdge) i.next(); - subgraph.add(de.getEdge()); - Node toNode = de.getToNode(); - if (! toNode.isVisited()) nodeStack.push(toNode); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/precision/CommonBits.java b/src/main/java/com/vividsolutions/jts/precision/CommonBits.java deleted file mode 100644 index b12de8dd5b..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/CommonBits.java +++ /dev/null @@ -1,160 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -/** - * Determines the maximum number of common most-significant - * bits in the mantissa of one or numbers. - * Can be used to compute the double-precision number which - * is represented by the common bits. - * If there are no common bits, the number computed is 0.0. - * - * @version 1.7 - */ -public class CommonBits { - - /** - * Computes the bit pattern for the sign and exponent of a - * double-precision number. - * - * @param num - * @return the bit pattern for the sign and exponent - */ - public static long signExpBits(long num) - { - return num >> 52; - } - - /** - * This computes the number of common most-significant bits in the mantissas - * of two double-precision numbers. - * It does not count the hidden bit, which is always 1. - * It does not determine whether the numbers have the same exponent - if they do - * not, the value computed by this function is meaningless. - * - * @param num1 the first number - * @param num2 the second number - * @return the number of common most-significant mantissa bits - */ - public static int numCommonMostSigMantissaBits(long num1, long num2) - { - int count = 0; - for (int i = 52; i >= 0; i--) - { - if (getBit(num1, i) != getBit(num2, i)) - return count; - count++; - } - return 52; - } - - /** - * Zeroes the lower n bits of a bitstring. - * - * @param bits the bitstring to alter - * @return the zeroed bitstring - */ - public static long zeroLowerBits(long bits, int nBits) - { - long invMask = (1L << nBits) - 1L; - long mask = ~ invMask; - long zeroed = bits & mask; - return zeroed; - } - - /** - * Extracts the i'th bit of a bitstring. - * - * @param bits the bitstring to extract from - * @param i the bit to extract - * @return the value of the extracted bit - */ - public static int getBit(long bits, int i) - { - long mask = (1L << i); - return (bits & mask) != 0 ? 1 : 0; - } - - private boolean isFirst = true; - private int commonMantissaBitsCount = 53; - private long commonBits = 0; - private long commonSignExp; - - public CommonBits() { - } - - public void add(double num) - { - long numBits = Double.doubleToLongBits(num); - if (isFirst) { - commonBits = numBits; - commonSignExp = signExpBits(commonBits); - isFirst = false; - return; - } - - long numSignExp = signExpBits(numBits); - if (numSignExp != commonSignExp) { - commonBits = 0; - return; - } - -// System.out.println(toString(commonBits)); -// System.out.println(toString(numBits)); - commonMantissaBitsCount = numCommonMostSigMantissaBits(commonBits, numBits); - commonBits = zeroLowerBits(commonBits, 64 - (12 + commonMantissaBitsCount)); -// System.out.println(toString(commonBits)); - } - - public double getCommon() - { - return Double.longBitsToDouble(commonBits); - } - /** - * A representation of the Double bits formatted for easy readability - */ - public String toString(long bits) - { - double x = Double.longBitsToDouble(bits); - String numStr = Long.toBinaryString(bits); - String padStr = "0000000000000000000000000000000000000000000000000000000000000000" + numStr; - String bitStr = padStr.substring(padStr.length() - 64); - String str = bitStr.substring(0, 1) + " " - + bitStr.substring(1, 12) + "(exp) " - + bitStr.substring(12) - + " [ " + x + " ]"; - return str; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/precision/CommonBitsOp.java b/src/main/java/com/vividsolutions/jts/precision/CommonBitsOp.java deleted file mode 100644 index 22036d4877..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/CommonBitsOp.java +++ /dev/null @@ -1,184 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; - -/** - * Provides versions of Geometry spatial functions which use - * common bit removal to reduce the likelihood of robustness problems. - *

                        - * In the current implementation no rounding is performed on the - * reshifted result geometry, which means that it is possible - * that the returned Geometry is invalid. - * Client classes should check the validity of the returned result themselves. - * - * @version 1.7 - */ -public class CommonBitsOp { - - private boolean returnToOriginalPrecision = true; - private CommonBitsRemover cbr; - - /** - * Creates a new instance of class, which reshifts result {@link Geometry}s. - */ - public CommonBitsOp() - { - this(true); - } - - /** - * Creates a new instance of class, specifying whether - * the result {@link Geometry}s should be reshifted. - * - * @param returnToOriginalPrecision - */ - public CommonBitsOp(boolean returnToOriginalPrecision) - { - this.returnToOriginalPrecision = returnToOriginalPrecision; - } - - /** - * Computes the set-theoretic intersection of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic intersection of the input Geometries. - */ - public Geometry intersection(Geometry geom0, Geometry geom1) - { - Geometry[] geom = removeCommonBits(geom0, geom1); - return computeResultPrecision(geom[0].intersection(geom[1])); - } - - /** - * Computes the set-theoretic union of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic union of the input Geometries. - */ - public Geometry union(Geometry geom0, Geometry geom1) - { - Geometry[] geom = removeCommonBits(geom0, geom1); - return computeResultPrecision(geom[0].union(geom[1])); - } - - /** - * Computes the set-theoretic difference of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry, to be subtracted from the first - * @return the Geometry representing the set-theoretic difference of the input Geometries. - */ - public Geometry difference(Geometry geom0, Geometry geom1) - { - Geometry[] geom = removeCommonBits(geom0, geom1); - return computeResultPrecision(geom[0].difference(geom[1])); - } - - /** - * Computes the set-theoretic symmetric difference of two geometries, - * using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic symmetric difference of the input Geometries. - */ - public Geometry symDifference(Geometry geom0, Geometry geom1) - { - Geometry[] geom = removeCommonBits(geom0, geom1); - return computeResultPrecision(geom[0].symDifference(geom[1])); - } - - /** - * Computes the buffer a geometry, - * using enhanced precision. - * @param geom0 the Geometry to buffer - * @param distance the buffer distance - * @return the Geometry representing the buffer of the input Geometry. - */ - public Geometry buffer(Geometry geom0, double distance) - { - Geometry geom = removeCommonBits(geom0); - return computeResultPrecision(geom.buffer(distance)); - } - - /** - * If required, returning the result to the orginal precision if required. - *

                        - * In this current implementation, no rounding is performed on the - * reshifted result geometry, which means that it is possible - * that the returned Geometry is invalid. - * - * @param result the result Geometry to modify - * @return the result Geometry with the required precision - */ - private Geometry computeResultPrecision(Geometry result) - { - if (returnToOriginalPrecision) - cbr.addCommonBits(result); - return result; - } - - /** - * Computes a copy of the input {@link Geometry} with the calculated common bits - * removed from each coordinate. - * @param geom0 the Geometry to remove common bits from - * @return a copy of the input Geometry with common bits removed - */ - private Geometry removeCommonBits(Geometry geom0) - { - cbr = new CommonBitsRemover(); - cbr.add(geom0); - Geometry geom = cbr.removeCommonBits((Geometry) geom0.clone()); - return geom; - } - - /** - * Computes a copy of each input {@link Geometry}s with the calculated common bits - * removed from each coordinate. - * @param geom0 a Geometry to remove common bits from - * @param geom1 a Geometry to remove common bits from - * @return an array containing copies - * of the input Geometry's with common bits removed - */ - private Geometry[] removeCommonBits(Geometry geom0, Geometry geom1) - { - cbr = new CommonBitsRemover(); - cbr.add(geom0); - cbr.add(geom1); - Geometry geom[] = new Geometry[2]; - geom[0] = cbr.removeCommonBits((Geometry) geom0.clone()); - geom[1] = cbr.removeCommonBits((Geometry) geom1.clone()); - return geom; - } -} diff --git a/src/main/java/com/vividsolutions/jts/precision/CommonBitsRemover.java b/src/main/java/com/vividsolutions/jts/precision/CommonBitsRemover.java deleted file mode 100644 index 8c77eb3032..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/CommonBitsRemover.java +++ /dev/null @@ -1,175 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; - -/** - * Removes common most-significant mantissa bits - * from one or more {@link Geometry}s. - *

                        - * The CommonBitsRemover "scavenges" precision - * which is "wasted" by a large displacement of the geometry - * from the origin. - * For example, if a small geometry is displaced from the origin - * by a large distance, - * the displacement increases the significant figures in the coordinates, - * but does not affect the relative topology of the geometry. - * Thus the geometry can be translated back to the origin - * without affecting its topology. - * In order to compute the translation without affecting - * the full precision of the coordinate values, - * the translation is performed at the bit level by - * removing the common leading mantissa bits. - *

                        - * If the geometry envelope already contains the origin, - * the translation procedure cannot be applied. - * In this case, the common bits value is computed as zero. - *

                        - * If the geometry crosses the Y axis but not the X axis - * (and mutatis mutandum), - * the common bits for Y are zero, - * but the common bits for X are non-zero. - * - * @version 1.7 - */ -public class CommonBitsRemover -{ - private Coordinate commonCoord; - private CommonCoordinateFilter ccFilter = new CommonCoordinateFilter(); - - public CommonBitsRemover() - { - } - - /** - * Add a geometry to the set of geometries whose common bits are - * being computed. After this method has executed the - * common coordinate reflects the common bits of all added - * geometries. - * - * @param geom a Geometry to test for common bits - */ - public void add(Geometry geom) - { - geom.apply(ccFilter); - commonCoord = ccFilter.getCommonCoordinate(); - } - - /** - * The common bits of the Coordinates in the supplied Geometries. - */ - public Coordinate getCommonCoordinate() { return commonCoord; } - - /** - * Removes the common coordinate bits from a Geometry. - * The coordinates of the Geometry are changed. - * - * @param geom the Geometry from which to remove the common coordinate bits - * @return the shifted Geometry - */ - public Geometry removeCommonBits(Geometry geom) - { - if (commonCoord.x == 0.0 && commonCoord.y == 0.0) - return geom; - Coordinate invCoord = new Coordinate(commonCoord); - invCoord.x = -invCoord.x; - invCoord.y = -invCoord.y; - Translater trans = new Translater(invCoord); - geom.apply(trans); - geom.geometryChanged(); - return geom; - } - - /** - * Adds the common coordinate bits back into a Geometry. - * The coordinates of the Geometry are changed. - * - * @param geom the Geometry to which to add the common coordinate bits - */ - public void addCommonBits(Geometry geom) - { - Translater trans = new Translater(commonCoord); - geom.apply(trans); - geom.geometryChanged(); - } - - class CommonCoordinateFilter - implements CoordinateFilter - { - private CommonBits commonBitsX = new CommonBits(); - private CommonBits commonBitsY = new CommonBits(); - - public void filter(Coordinate coord) - { - commonBitsX.add(coord.x); - commonBitsY.add(coord.y); - } - - public Coordinate getCommonCoordinate() - { - return new Coordinate( - commonBitsX.getCommon(), - commonBitsY.getCommon()); - } - } - - class Translater - implements CoordinateSequenceFilter - { - Coordinate trans = null; - - public Translater(Coordinate trans) - { - this.trans = trans; - } - - public void filter(CoordinateSequence seq, int i) { - double xp = seq.getOrdinate(i, 0) + trans.x; - double yp = seq.getOrdinate(i, 1) + trans.y; - seq.setOrdinate(i, 0, xp); - seq.setOrdinate(i, 1, yp); - } - - public boolean isDone() { - return false; - } - - public boolean isGeometryChanged() { - return true; - } - - } - -} diff --git a/src/main/java/com/vividsolutions/jts/precision/CoordinatePrecisionReducerFilter.java b/src/main/java/com/vividsolutions/jts/precision/CoordinatePrecisionReducerFilter.java deleted file mode 100644 index 5d4f6eff5c..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/CoordinatePrecisionReducerFilter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; - -/** - * Reduces the precision of the {@link Coordinate}s in a - * {@link CoordinateSequence} to match the supplied {@link PrecisionModel}. - * Uses {@link PrecisionModel#makePrecise(double)}. - * The input is modified in-place, so - * it should be cloned beforehand if the - * original should not be modified. - * - * @author mbdavis - * - */ -public class CoordinatePrecisionReducerFilter - implements CoordinateSequenceFilter -{ - private PrecisionModel precModel; - - /** - * Creates a new precision reducer filter. - * - * @param precModel the PrecisionModel to use - */ - public CoordinatePrecisionReducerFilter(PrecisionModel precModel) - { - this.precModel = precModel; - } - - /** - * Rounds the Coordinates in the sequence to match the PrecisionModel - */ - public void filter(CoordinateSequence seq, int i) - { - seq.setOrdinate(i, 0, precModel.makePrecise(seq.getOrdinate(i, 0))); - seq.setOrdinate(i, 1, precModel.makePrecise(seq.getOrdinate(i, 1))); - } - - /** - * Always runs over all geometry components. - * - * @return false - */ - public boolean isDone() { return false; } - - /** - * Always reports that the geometry has changed - * - * @return true - */ - public boolean isGeometryChanged() { return true; } -} diff --git a/src/main/java/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java b/src/main/java/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java deleted file mode 100644 index f90775241f..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java +++ /dev/null @@ -1,226 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.operation.overlay.OverlayOp; - -/** - * Provides versions of Geometry spatial functions which use - * enhanced precision techniques to reduce the likelihood of robustness problems. - * - * @version 1.7 - */ -public class EnhancedPrecisionOp -{ - /** - * Computes the set-theoretic intersection of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic intersection of the input Geometries. - */ - public static Geometry intersection(Geometry geom0, Geometry geom1) - { - RuntimeException originalEx; - try { - Geometry result = geom0.intersection(geom1); - return result; - } - catch (RuntimeException ex) - { - originalEx = ex; - } - /* - * If we are here, the original op encountered a precision problem - * (or some other problem). Retry the operation with - * enhanced precision to see if it succeeds - */ - try { - CommonBitsOp cbo = new CommonBitsOp(true); - Geometry resultEP = cbo.intersection(geom0, geom1); - // check that result is a valid geometry after the reshift to orginal precision - if (! resultEP.isValid()) - throw originalEx; - return resultEP; - } - catch (RuntimeException ex2) - { - throw originalEx; - } - } - /** - * Computes the set-theoretic union of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic union of the input Geometries. - */ - public static Geometry union(Geometry geom0, Geometry geom1) - { - RuntimeException originalEx; - try { - Geometry result = geom0.union(geom1); - return result; - } - catch (RuntimeException ex) - { - originalEx = ex; - } - /* - * If we are here, the original op encountered a precision problem - * (or some other problem). Retry the operation with - * enhanced precision to see if it succeeds - */ - try { - CommonBitsOp cbo = new CommonBitsOp(true); - Geometry resultEP = cbo.union(geom0, geom1); - // check that result is a valid geometry after the reshift to orginal precision - if (! resultEP.isValid()) - throw originalEx; - return resultEP; - } - catch (RuntimeException ex2) - { - throw originalEx; - } - } - /** - * Computes the set-theoretic difference of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic difference of the input Geometries. - */ - public static Geometry difference(Geometry geom0, Geometry geom1) - { - RuntimeException originalEx; - try { - Geometry result = geom0.difference(geom1); - return result; - } - catch (RuntimeException ex) - { - originalEx = ex; - } - /* - * If we are here, the original op encountered a precision problem - * (or some other problem). Retry the operation with - * enhanced precision to see if it succeeds - */ - try { - CommonBitsOp cbo = new CommonBitsOp(true); - Geometry resultEP = cbo.difference(geom0, geom1); - // check that result is a valid geometry after the reshift to orginal precision - if (! resultEP.isValid()) - throw originalEx; - return resultEP; - } - catch (RuntimeException ex2) - { - throw originalEx; - } - } - /** - * Computes the set-theoretic symmetric difference of two {@link Geometry}s, using enhanced precision. - * @param geom0 the first Geometry - * @param geom1 the second Geometry - * @return the Geometry representing the set-theoretic symmetric difference of the input Geometries. - */ - public static Geometry symDifference(Geometry geom0, Geometry geom1) - { - RuntimeException originalEx; - try { - Geometry result = geom0.symDifference(geom1); - return result; - } - catch (RuntimeException ex) - { - originalEx = ex; - } - /* - * If we are here, the original op encountered a precision problem - * (or some other problem). Retry the operation with - * enhanced precision to see if it succeeds - */ - try { - CommonBitsOp cbo = new CommonBitsOp(true); - Geometry resultEP = cbo.symDifference(geom0, geom1); - // check that result is a valid geometry after the reshift to orginal precision - if (! resultEP.isValid()) - throw originalEx; - return resultEP; - } - catch (RuntimeException ex2) - { - throw originalEx; - } - } - /** - * Computes the buffer of a {@link Geometry}, using enhanced precision. - * This method should no longer be necessary, since the buffer algorithm - * now is highly robust. - * - * @param geom the first Geometry - * @param distance the buffer distance - * @return the Geometry representing the buffer of the input Geometry. - */ - public static Geometry buffer(Geometry geom, double distance) - { - RuntimeException originalEx; - try { - Geometry result = geom.buffer(distance); - return result; - } - catch (RuntimeException ex) - { - originalEx = ex; - } - /* - * If we are here, the original op encountered a precision problem - * (or some other problem). Retry the operation with - * enhanced precision to see if it succeeds - */ - try { - CommonBitsOp cbo = new CommonBitsOp(true); - Geometry resultEP = cbo.buffer(geom, distance); - // check that result is a valid geometry after the reshift to orginal precision - if (! resultEP.isValid()) - throw originalEx; - return resultEP; - } - catch (RuntimeException ex2) - { - throw originalEx; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java b/src/main/java/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java deleted file mode 100644 index 52189eabea..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java +++ /dev/null @@ -1,235 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Reduces the precision of a {@link Geometry} - * according to the supplied {@link PrecisionModel}, - * ensuring that the result is topologically valid. - * - * @version 1.12 - */ -public class GeometryPrecisionReducer -{ - /** - * Convenience method for doing precision reduction - * on a single geometry, - * with collapses removed - * and keeping the geometry precision model the same, - * and preserving polygonal topology. - * - * @param g the geometry to reduce - * @param precModel the precision model to use - * @return the reduced geometry - */ - public static Geometry reduce(Geometry g, PrecisionModel precModel) - { - GeometryPrecisionReducer reducer = new GeometryPrecisionReducer(precModel); - return reducer.reduce(g); - } - - /** - * Convenience method for doing pointwise precision reduction - * on a single geometry, - * with collapses removed - * and keeping the geometry precision model the same, - * but NOT preserving valid polygonal topology. - * - * @param g the geometry to reduce - * @param precModel the precision model to use - * @return the reduced geometry - */ - public static Geometry reducePointwise(Geometry g, PrecisionModel precModel) - { - GeometryPrecisionReducer reducer = new GeometryPrecisionReducer(precModel); - reducer.setPointwise(true); - return reducer.reduce(g); - } - - private PrecisionModel targetPM; - private boolean removeCollapsed = true; - private boolean changePrecisionModel = false; - private boolean isPointwise = false; - - public GeometryPrecisionReducer(PrecisionModel pm) - { - targetPM = pm; - } - - /** - * Sets whether the reduction will result in collapsed components - * being removed completely, or simply being collapsed to an (invalid) - * Geometry of the same type. - * The default is to remove collapsed components. - * - * @param removeCollapsed if true collapsed components will be removed - */ - public void setRemoveCollapsedComponents(boolean removeCollapsed) - { - this.removeCollapsed = removeCollapsed; - } - - /** - * Sets whether the {@link PrecisionModel} of the new reduced Geometry - * will be changed to be the {@link PrecisionModel} supplied to - * specify the precision reduction. - *

                        - * The default is to not change the precision model - * - * @param changePrecisionModel if true the precision model of the created Geometry will be the - * the precisionModel supplied in the constructor. - */ - public void setChangePrecisionModel(boolean changePrecisionModel) - { - this.changePrecisionModel = changePrecisionModel; - } - - /** - * Sets whether the precision reduction will be done - * in pointwise fashion only. - * Pointwise precision reduction reduces the precision - * of the individual coordinates only, but does - * not attempt to recreate valid topology. - * This is only relevant for geometries containing polygonal components. - * - * @param isPointwise if reduction should be done pointwise only - */ - public void setPointwise(boolean isPointwise) - { - this.isPointwise = isPointwise; - } - - public Geometry reduce(Geometry geom) - { - Geometry reducePW = reducePointwise(geom); - if (isPointwise) - return reducePW; - - //TODO: handle GeometryCollections containing polys - if (! (reducePW instanceof Polygonal)) - return reducePW; - - // Geometry is polygonal - test if topology needs to be fixed - if (reducePW.isValid()) return reducePW; - - // hack to fix topology. - // TODO: implement snap-rounding and use that. - return fixPolygonalTopology(reducePW); - } - - private Geometry reducePointwise(Geometry geom) - { - GeometryEditor geomEdit; - if (changePrecisionModel) { - GeometryFactory newFactory = createFactory(geom.getFactory(), targetPM); - geomEdit = new GeometryEditor(newFactory); - } - else - // don't change geometry factory - geomEdit = new GeometryEditor(); - - /** - * For polygonal geometries, collapses are always removed, in order - * to produce correct topology - */ - boolean finalRemoveCollapsed = removeCollapsed; - if (geom.getDimension() >= 2) - finalRemoveCollapsed = true; - - Geometry reduceGeom = geomEdit.edit(geom, - new PrecisionReducerCoordinateOperation(targetPM, finalRemoveCollapsed)); - - return reduceGeom; - } - - private Geometry fixPolygonalTopology(Geometry geom) - { - /** - * If precision model was *not* changed, need to flip - * geometry to targetPM, buffer in that model, then flip back - */ - Geometry geomToBuffer = geom; - if (! changePrecisionModel) { - geomToBuffer = changePM(geom, targetPM); - } - - Geometry bufGeom = geomToBuffer.buffer(0); - - Geometry finalGeom = bufGeom; - if (! changePrecisionModel) { - // a slick way to copy the geometry with the original precision factory - finalGeom = geom.getFactory().createGeometry(bufGeom); - } - return finalGeom; - } - - /** - * Duplicates a geometry to one that uses a different PrecisionModel, - * without changing any coordinate values. - * - * @param geom the geometry to duplicate - * @param newPM the precision model to use - * @return the geometry value with a new precision model - */ - private Geometry changePM(Geometry geom, PrecisionModel newPM) - { - GeometryEditor geomEditor = createEditor(geom.getFactory(), newPM); - // this operation changes the PM for the entire geometry tree - return geomEditor.edit(geom, new GeometryEditor.NoOpGeometryOperation()); - } - - private GeometryEditor createEditor(GeometryFactory geomFactory, PrecisionModel newPM) - { - // no need to change if precision model is the same - if (geomFactory.getPrecisionModel() == newPM) - return new GeometryEditor(); - // otherwise create a geometry editor which changes PrecisionModel - GeometryFactory newFactory = createFactory(geomFactory, newPM); - GeometryEditor geomEdit = new GeometryEditor(newFactory); - return geomEdit; - } - - private GeometryFactory createFactory(GeometryFactory inputFactory, PrecisionModel pm) - { - GeometryFactory newFactory - = new GeometryFactory(pm, - inputFactory.getSRID(), - inputFactory.getCoordinateSequenceFactory()); - return newFactory; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/precision/MinimumClearance.java b/src/main/java/com/vividsolutions/jts/precision/MinimumClearance.java deleted file mode 100644 index e30f81229e..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/MinimumClearance.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.LineSegment; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Lineal; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.index.strtree.ItemBoundable; -import com.vividsolutions.jts.index.strtree.ItemDistance; -import com.vividsolutions.jts.index.strtree.STRtree; -import com.vividsolutions.jts.operation.distance.FacetSequence; -import com.vividsolutions.jts.operation.distance.FacetSequenceTreeBuilder; - -/** - * Computes the Minimum Clearance of a {@link Geometry}. - *

                        - * The Minimum Clearance is a measure of - * what magnitude of perturbation of - * the vertices of a geometry can be tolerated - * before the geometry becomes topologically invalid. - * The smaller the Minimum Clearance distance, - * the less vertex pertubation the geometry can tolerate - * before becoming invalid. - *

                        - * The concept was introduced by Thompson and Van Oosterom - * [TV06], based on earlier work by Milenkovic [Mi88]. - *

                        - * The Minimum Clearance of a geometry G - * is defined to be the value r - * such that "the movement of all points by a distance - * of r in any direction will - * guarantee to leave the geometry valid" [TV06]. - * An equivalent constructive definition [Mi88] is that - * r is the largest value such: - *

                          - *
                        1. No two distinct vertices of G are closer than r - *
                        2. No vertex of G is closer than r to an edge of G - * of which the vertex is not an endpoint - *
                        - * The following image shows an example of the Minimum Clearance - * of a simple polygon. - *

                        - *

                        - *

                        - * If G has only a single vertex (i.e. is a - * {@link Point}), the value of the minimum clearance - * is {@link Double#MAX_VALUE}. - *

                        - * If G is a {@link Puntal} or {@link Lineal} geometry, - * then in fact no amount of perturbation - * will render the geometry invalid. - * In this case a Minimum Clearance is still computed - * based on the vertex and segment distances - * according to the constructive definition. - *

                        - * It is possible for no Minimum Clearance to exist. - * For instance, a {@link MultiPoint} with all members identical - * has no Minimum Clearance - * (i.e. no amount of perturbation will cause - * the member points to become non-identical). - * Empty geometries also have no such distance. - * The lack of a meaningful MinimumClearance distance is detected - * and suitable values are returned by - * {@link #getDistance()} and {@link #getLine()}. - *

                        - * The computation of Minimum Clearance utilizes - * the {@link STRtree#nearestNeighbour(ItemDistance)} - * method to provide good performance even for - * large inputs. - *

                        - * An interesting note is that for the case of {@link MultiPoint}s, - * the computed Minimum Clearance line - * effectively determines the Nearest Neighbours in the collection. - * - *

                        References

                        - *
                          - *
                        • [Mi88] Milenkovic, V. J., - * Verifiable implementations of geometric algorithms - * using finite precision arithmetic. - * in Artificial Intelligence, 377-401. 1988 - *
                        • [TV06] Thompson, Rod and van Oosterom, Peter, - * Interchange of Spatial Data-Inhibiting Factors, - * Agile 2006, Visegrad, Hungary. 2006 - *
                        - * - * @author Martin Davis - * - */ -public class MinimumClearance -{ - /** - * Computes the Minimum Clearance distance for - * the given Geometry. - * - * @param g the input geometry - * @return the Minimum Clearance distance - */ - public static double getDistance(Geometry g) - { - MinimumClearance rp = new MinimumClearance(g); - return rp.getDistance(); - } - - /** - * Gets a LineString containing two points - * which are at the Minimum Clearance distance - * for the given Geometry. - * - * @param g the input geometry - * @return the value of the minimum clearance distance - * or LINESTRING EMPTY if no Minimum Clearance distance exists - */ - public static Geometry getLine(Geometry g) - { - MinimumClearance rp = new MinimumClearance(g); - return rp.getLine(); - } - - private Geometry inputGeom; - private double minClearance; - private Coordinate[] minClearancePts; - - /** - * Creates an object to compute the Minimum Clearance - * for the given Geometry - * - * @param geom the input geometry - */ - public MinimumClearance(Geometry geom) - { - inputGeom = geom; - } - - /** - * Gets the Minimum Clearance distance. - *

                        - * If no distance exists - * (e.g. in the case of two identical points) - * Double.MAX_VALUE is returned. - * - * @return the value of the minimum clearance distance - * or Double.MAX_VALUE if no Minimum Clearance distance exists - */ - public double getDistance() - { - compute(); - return minClearance; - } - - /** - * Gets a LineString containing two points - * which are at the Minimum Clearance distance. - *

                        - * If no distance could be found - * (e.g. in the case of two identical points) - * LINESTRING EMPTY is returned. - * - * @return the value of the minimum clearance distance - * or LINESTRING EMPTY if no Minimum Clearance distance exists - */ - public LineString getLine() - { - compute(); - // return empty line string if no min pts where found - if (minClearancePts == null || minClearancePts[0] == null) - return inputGeom.getFactory().createLineString((Coordinate[]) null); - return inputGeom.getFactory().createLineString(minClearancePts); - } - - private void compute() - { - // already computed - if (minClearancePts != null) return; - - // initialize to "No Distance Exists" state - minClearancePts = new Coordinate[2]; - minClearance = Double.MAX_VALUE; - - // handle empty geometries - if (inputGeom.isEmpty()) { - return; - } - - STRtree geomTree = FacetSequenceTreeBuilder.build(inputGeom); - - Object[] nearest = geomTree.nearestNeighbour(new MinClearanceDistance()); - MinClearanceDistance mcd = new MinClearanceDistance(); - minClearance = mcd.distance( - (FacetSequence) nearest[0], - (FacetSequence) nearest[1]); - minClearancePts = mcd.getCoordinates(); - } - - /** - * Implements the MinimumClearance distance function: - *

                          - *
                        • dist(p1, p2) = - *
                            - *
                          • p1 != p2 : p1.distance(p2) - *
                          • p1 == p2 : Double.MAX - *
                          - *
                        • dist(p, seg) = - *
                            - *
                          • p != seq.p1 && p != seg.p2 : seg.distance(p) - *
                          • ELSE : Double.MAX - *
                          - *
                        - * Also computes the values of the nearest points, if any. - * - * @author Martin Davis - * - */ - private static class MinClearanceDistance - implements ItemDistance - { - private double minDist = Double.MAX_VALUE; - private Coordinate[] minPts = new Coordinate[2]; - - public Coordinate[] getCoordinates() - { - return minPts; - } - - public double distance(ItemBoundable b1, ItemBoundable b2) { - FacetSequence fs1 = (FacetSequence) b1.getItem(); - FacetSequence fs2 = (FacetSequence) b2.getItem(); - minDist = Double.MAX_VALUE; - return distance(fs1, fs2); - } - - public double distance(FacetSequence fs1, FacetSequence fs2) { - - // compute MinClearance distance metric - - vertexDistance(fs1, fs2); - if (fs1.size() == 1 && fs2.size() == 1) return minDist; - if (minDist <= 0.0) return minDist; - segmentDistance(fs1, fs2); - if (minDist <= 0.0) return minDist; - segmentDistance(fs2, fs1); - return minDist; - } - - private double vertexDistance(FacetSequence fs1, FacetSequence fs2) { - for (int i1 = 0; i1 < fs1.size(); i1++) { - for (int i2 = 0; i2 < fs2.size(); i2++) { - Coordinate p1 = fs1.getCoordinate(i1); - Coordinate p2 = fs2.getCoordinate(i2); - if (! p1.equals2D(p2)) { - double d = p1.distance(p2); - if (d < minDist) { - minDist = d; - minPts[0] = p1; - minPts[1] = p2; - if (d == 0.0) - return d; - } - } - } - } - return minDist; - } - - private double segmentDistance(FacetSequence fs1, FacetSequence fs2) { - for (int i1 = 0; i1 < fs1.size(); i1++) { - for (int i2 = 1; i2 < fs2.size(); i2++) { - - Coordinate p = fs1.getCoordinate(i1); - - Coordinate seg0 = fs2.getCoordinate(i2-1); - Coordinate seg1 = fs2.getCoordinate(i2); - - if (! (p.equals2D(seg0) || p.equals2D(seg1))) { - double d = CGAlgorithms.distancePointLine(p, seg0, seg1); - if (d < minDist) { - minDist = d; - updatePts(p, seg0, seg1); - if (d == 0.0) - return d; - } - } - } - } - return minDist; - } - - private void updatePts(Coordinate p, Coordinate seg0, Coordinate seg1) - { - minPts[0] = p; - LineSegment seg = new LineSegment(seg0, seg1); - minPts[1] = new Coordinate(seg.closestPoint(p)); - } - - - } - - - } - - diff --git a/src/main/java/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java b/src/main/java/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java deleted file mode 100644 index a12f89ebd4..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateList; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.LinearRing; -import com.vividsolutions.jts.geom.PrecisionModel; -import com.vividsolutions.jts.geom.util.GeometryEditor; - -public class PrecisionReducerCoordinateOperation extends - GeometryEditor.CoordinateOperation -{ - private PrecisionModel targetPM; - private boolean removeCollapsed = true; - - public PrecisionReducerCoordinateOperation(PrecisionModel targetPM, boolean removeCollapsed) - { - this.targetPM = targetPM; - this.removeCollapsed = removeCollapsed; - } - - public Coordinate[] edit(Coordinate[] coordinates, Geometry geom) { - if (coordinates.length == 0) - return null; - - Coordinate[] reducedCoords = new Coordinate[coordinates.length]; - // copy coordinates and reduce - for (int i = 0; i < coordinates.length; i++) { - Coordinate coord = new Coordinate(coordinates[i]); - targetPM.makePrecise(coord); - reducedCoords[i] = coord; - } - // remove repeated points, to simplify returned geometry as much as possible - CoordinateList noRepeatedCoordList = new CoordinateList(reducedCoords, - false); - Coordinate[] noRepeatedCoords = noRepeatedCoordList.toCoordinateArray(); - - /** - * Check to see if the removal of repeated points collapsed the coordinate - * List to an invalid length for the type of the parent geometry. It is not - * necessary to check for Point collapses, since the coordinate list can - * never collapse to less than one point. If the length is invalid, return - * the full-length coordinate array first computed, or null if collapses are - * being removed. (This may create an invalid geometry - the client must - * handle this.) - */ - int minLength = 0; - if (geom instanceof LineString) - minLength = 2; - if (geom instanceof LinearRing) - minLength = 4; - - Coordinate[] collapsedCoords = reducedCoords; - if (removeCollapsed) - collapsedCoords = null; - - // return null or orginal length coordinate array - if (noRepeatedCoords.length < minLength) { - return collapsedCoords; - } - - // ok to return shorter coordinate array - return noRepeatedCoords; - } -} diff --git a/src/main/java/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java b/src/main/java/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java deleted file mode 100644 index dfeb4a3f6b..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java +++ /dev/null @@ -1,167 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Reduces the precision of the coordinates of a {@link Geometry} - * according to the supplied {@link PrecisionModel}, without - * attempting to preserve valid topology. - *

                        - * In the case of {@link Polygonal} geometries, - * the topology of the resulting geometry may be invalid if - * topological collapse occurs due to coordinates being shifted. - * It is up to the client to check this and handle it if necessary. - * Collapses may not matter for some uses. An example - * is simplifying the input to the buffer algorithm. - * The buffer algorithm does not depend on the validity of the input geometry. - * - * @version 1.7 - * - * @deprecated use GeometryPrecisionReducer - */ -public class SimpleGeometryPrecisionReducer -{ - /** - * Convenience method for doing precision reduction on a single geometry, - * with collapses removed and keeping the geometry precision model the same. - * - * @param g - * @param precModel - * @return the reduced geometry - */ - public static Geometry reduce(Geometry g, PrecisionModel precModel) - { - SimpleGeometryPrecisionReducer reducer = new SimpleGeometryPrecisionReducer(precModel); - return reducer.reduce(g); - } - - private PrecisionModel newPrecisionModel; - private boolean removeCollapsed = true; - private boolean changePrecisionModel = false; - - public SimpleGeometryPrecisionReducer(PrecisionModel pm) - { - newPrecisionModel = pm; - } - - /** - * Sets whether the reduction will result in collapsed components - * being removed completely, or simply being collapsed to an (invalid) - * Geometry of the same type. - * The default is to remove collapsed components. - * - * @param removeCollapsed if true collapsed components will be removed - */ - public void setRemoveCollapsedComponents(boolean removeCollapsed) - { - this.removeCollapsed = removeCollapsed; - } - - /** - * Sets whether the {@link PrecisionModel} of the new reduced Geometry - * will be changed to be the {@link PrecisionModel} supplied to - * specify the precision reduction. - *

                        - * The default is to not change the precision model - * - * @param changePrecisionModel if true the precision model of the created Geometry will be the - * the precisionModel supplied in the constructor. - */ - public void setChangePrecisionModel(boolean changePrecisionModel) - { - this.changePrecisionModel = changePrecisionModel; - } - - public Geometry reduce(Geometry geom) - { - GeometryEditor geomEdit; - if (changePrecisionModel) { - GeometryFactory newFactory = new GeometryFactory(newPrecisionModel, geom.getFactory().getSRID()); - geomEdit = new GeometryEditor(newFactory); - } - else - // don't change geometry factory - geomEdit = new GeometryEditor(); - - return geomEdit.edit(geom, new PrecisionReducerCoordinateOperation()); - } - - private class PrecisionReducerCoordinateOperation - extends GeometryEditor.CoordinateOperation - { - public Coordinate[] edit(Coordinate[] coordinates, Geometry geom) - { - if (coordinates.length == 0) return null; - - Coordinate[] reducedCoords = new Coordinate[coordinates.length]; - // copy coordinates and reduce - for (int i = 0; i < coordinates.length; i++) { - Coordinate coord = new Coordinate(coordinates[i]); - newPrecisionModel.makePrecise(coord); - reducedCoords[i] = coord; - } - // remove repeated points, to simplify returned geometry as much as possible - CoordinateList noRepeatedCoordList = new CoordinateList(reducedCoords, false); - Coordinate[] noRepeatedCoords = noRepeatedCoordList.toCoordinateArray(); - - /** - * Check to see if the removal of repeated points - * collapsed the coordinate List to an invalid length - * for the type of the parent geometry. - * It is not necessary to check for Point collapses, since the coordinate list can - * never collapse to less than one point. - * If the length is invalid, return the full-length coordinate array - * first computed, or null if collapses are being removed. - * (This may create an invalid geometry - the client must handle this.) - */ - int minLength = 0; - if (geom instanceof LineString) minLength = 2; - if (geom instanceof LinearRing) minLength = 4; - - Coordinate[] collapsedCoords = reducedCoords; - if (removeCollapsed) collapsedCoords = null; - - // return null or orginal length coordinate array - if (noRepeatedCoords.length < minLength) { - return collapsedCoords; - } - - // ok to return shorter coordinate array - return noRepeatedCoords; - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/precision/SimpleMinimumClearance.java b/src/main/java/com/vividsolutions/jts/precision/SimpleMinimumClearance.java deleted file mode 100644 index cbdab9d413..0000000000 --- a/src/main/java/com/vividsolutions/jts/precision/SimpleMinimumClearance.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.precision; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateFilter; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.CoordinateSequenceFilter; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.LineSegment; -import com.vividsolutions.jts.geom.LineString; - -/** - * Computes the minimum clearance of a geometry or - * set of geometries. - *

                        - * The Minimum Clearance is a measure of - * what magnitude of perturbation of its vertices can be tolerated - * by a geometry before it becomes topologically invalid. - *

                        - * This class uses an inefficient O(N^2) scan. - * It is primarily for testing purposes. - * - * - * @see MinimumClearance - * @author Martin Davis - * - */ -public class SimpleMinimumClearance -{ - public static double getDistance(Geometry g) - { - SimpleMinimumClearance rp = new SimpleMinimumClearance(g); - return rp.getDistance(); - } - - public static Geometry getLine(Geometry g) - { - SimpleMinimumClearance rp = new SimpleMinimumClearance(g); - return rp.getLine(); - } - - private Geometry inputGeom; - private double minClearance; - private Coordinate[] minClearancePts; - - public SimpleMinimumClearance(Geometry geom) - { - inputGeom = geom; - } - - public double getDistance() - { - compute(); - return minClearance; - } - - public LineString getLine() - { - compute(); - return inputGeom.getFactory().createLineString(minClearancePts); - } - - private void compute() - { - if (minClearancePts != null) return; - minClearancePts = new Coordinate[2]; - minClearance = Double.MAX_VALUE; - inputGeom.apply(new VertexCoordinateFilter()); - } - - private void updateClearance(double candidateValue, Coordinate p0, Coordinate p1) - { - if (candidateValue < minClearance) { - minClearance = candidateValue; - minClearancePts[0] = new Coordinate(p0); - minClearancePts[1] = new Coordinate(p1); - } - } - - private void updateClearance(double candidateValue, Coordinate p, - Coordinate seg0, Coordinate seg1) - { - if (candidateValue < minClearance) { - minClearance = candidateValue; - minClearancePts[0] = new Coordinate(p); - LineSegment seg = new LineSegment(seg0, seg1); - minClearancePts[1] = new Coordinate(seg.closestPoint(p)); - } - } - - private class VertexCoordinateFilter - implements CoordinateFilter - { - public VertexCoordinateFilter() - { - - } - - public void filter(Coordinate coord) { - inputGeom.apply(new ComputeMCCoordinateSequenceFilter(coord)); - } - } - - private class ComputeMCCoordinateSequenceFilter - implements CoordinateSequenceFilter - { - private Coordinate queryPt; - - public ComputeMCCoordinateSequenceFilter(Coordinate queryPt) - { - this.queryPt = queryPt; - } - public void filter(CoordinateSequence seq, int i) { - // compare to vertex - checkVertexDistance(seq.getCoordinate(i)); - - // compare to segment, if this is one - if (i > 0) { - checkSegmentDistance(seq.getCoordinate(i - 1), seq.getCoordinate(i)); - } - } - - private void checkVertexDistance(Coordinate vertex) - { - double vertexDist = vertex.distance(queryPt); - if (vertexDist > 0) { - updateClearance(vertexDist, queryPt, vertex); - } - } - - private void checkSegmentDistance(Coordinate seg0, Coordinate seg1) - { - if (queryPt.equals2D(seg0) || queryPt.equals2D(seg1)) - return; - double segDist = CGAlgorithms.distancePointLine(queryPt, seg1, seg0); - if (segDist > 0) - updateClearance(segDist, queryPt, seg1, seg0); - } - - public boolean isDone() { - return false; - } - - public boolean isGeometryChanged() { - return false; - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/shape/GeometricShapeBuilder.java b/src/main/java/com/vividsolutions/jts/shape/GeometricShapeBuilder.java deleted file mode 100644 index a089bf2525..0000000000 --- a/src/main/java/com/vividsolutions/jts/shape/GeometricShapeBuilder.java +++ /dev/null @@ -1,111 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.shape; - -import com.vividsolutions.jts.geom.*; - -public abstract class GeometricShapeBuilder -{ - protected Envelope extent = new Envelope(0, 1, 0, 1); - protected int numPts = 0; - protected GeometryFactory geomFactory; - - public GeometricShapeBuilder(GeometryFactory geomFactory) - { - this.geomFactory = geomFactory; - } - - public void setExtent(Envelope extent) - { - this.extent = extent; - } - - public Envelope getExtent() - { - return extent; - } - - public Coordinate getCentre() - { - return extent.centre(); - } - - public double getDiameter() - { - return Math.min(extent.getHeight(), extent.getWidth()); - } - - public double getRadius() - { - return getDiameter() / 2; - } - - public LineSegment getSquareBaseLine() - { - double radius = getRadius(); - - Coordinate centre = getCentre(); - Coordinate p0 = new Coordinate(centre.x - radius, centre.y - radius); - Coordinate p1 = new Coordinate(centre.x + radius, centre.y - radius); - return new LineSegment(p0, p1); - } - - public Envelope getSquareExtent() - { - double radius = getRadius(); - - Coordinate centre = getCentre(); - return new Envelope(centre.x - radius, centre.x + radius, - centre.y - radius, centre.y + radius); - } - - - /** - * Sets the total number of points in the created {@link Geometry}. - * The created geometry will have no more than this number of points, - * unless more are needed to create a valid geometry. - */ - public void setNumPoints(int numPts) { this.numPts = numPts; } - - public abstract Geometry getGeometry(); - - protected Coordinate createCoord(double x, double y) - { - Coordinate pt = new Coordinate(x, y); - geomFactory.getPrecisionModel().makePrecise(pt); - return pt; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java b/src/main/java/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java deleted file mode 100644 index 9fc4595dae..0000000000 --- a/src/main/java/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java +++ /dev/null @@ -1,120 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.shape.fractal; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.math.Vector2D; -import com.vividsolutions.jts.shape.*; - -public class KochSnowflakeBuilder -extends GeometricShapeBuilder -{ - private CoordinateList coordList = new CoordinateList(); - - public KochSnowflakeBuilder(GeometryFactory geomFactory) - { - super(geomFactory); - } - - public static int recursionLevelForSize(int numPts) - { - double pow4 = numPts / 3; - double exp = Math.log(pow4)/Math.log(4); - return (int) exp; - } - - public Geometry getGeometry() - { - int level = recursionLevelForSize(numPts); - LineSegment baseLine = getSquareBaseLine(); - Coordinate[] pts = getBoundary(level, baseLine.getCoordinate(0), baseLine.getLength()); - return geomFactory.createPolygon( - geomFactory.createLinearRing(pts), null); - } - - /** - * The height of an equilateral triangle of side one - */ - private static final double HEIGHT_FACTOR = Math.sin(Math.PI / 3.0); - private static final double ONE_THIRD = 1.0/3.0; - private static final double THIRD_HEIGHT = HEIGHT_FACTOR/3.0; - private static final double TWO_THIRDS = 2.0/3.0; - - private Coordinate[] getBoundary(int level, Coordinate origin, double width) - { - double y = origin.y; - // for all levels beyond 0 need to vertically shift shape by height of one "arm" to centre it - if (level > 0) { - y += THIRD_HEIGHT * width; - } - - Coordinate p0 = new Coordinate(origin.x, y); - Coordinate p1 = new Coordinate(origin.x + width/2, y + width * HEIGHT_FACTOR); - Coordinate p2 = new Coordinate(origin.x + width, y); - addSide(level, p0, p1); - addSide(level, p1, p2); - addSide(level, p2, p0); - coordList.closeRing(); - return coordList.toCoordinateArray(); - } - - public void addSide(int level, Coordinate p0, Coordinate p1) { - if (level == 0) - addSegment(p0, p1); - else { - Vector2D base = Vector2D.create(p0, p1); - Coordinate midPt = base.multiply(0.5).translate(p0); - - Vector2D heightVec = base.multiply(THIRD_HEIGHT); - Vector2D offsetVec = heightVec.rotateByQuarterCircle(1); - Coordinate offsetPt = offsetVec.translate(midPt); - - int n2 = level - 1; - Coordinate thirdPt = base.multiply(ONE_THIRD).translate(p0); - Coordinate twoThirdPt = base.multiply(TWO_THIRDS).translate(p0); - - // construct sides recursively - addSide(n2, p0, thirdPt); - addSide(n2, thirdPt, offsetPt); - addSide(n2, offsetPt, twoThirdPt); - addSide(n2, twoThirdPt, p1); - } - } - - private void addSegment(Coordinate p0, Coordinate p1) - { - coordList.add(p1); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java b/src/main/java/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java deleted file mode 100644 index 720e447366..0000000000 --- a/src/main/java/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java +++ /dev/null @@ -1,113 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.shape.fractal; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.shape.*; - -public class SierpinskiCarpetBuilder -extends GeometricShapeBuilder -{ - private CoordinateList coordList = new CoordinateList(); - - public SierpinskiCarpetBuilder(GeometryFactory geomFactory) - { - super(geomFactory); - } - - public static int recursionLevelForSize(int numPts) - { - double pow4 = numPts / 3; - double exp = Math.log(pow4)/Math.log(4); - return (int) exp; - } - - public Geometry getGeometry() - { - int level = recursionLevelForSize(numPts); - LineSegment baseLine = getSquareBaseLine(); - Coordinate origin = baseLine.getCoordinate(0); - LinearRing[] holes = getHoles(level, origin.x, origin.y, getDiameter()); - LinearRing shell = (LinearRing) ((Polygon) geomFactory.toGeometry(getSquareExtent())).getExteriorRing(); - return geomFactory.createPolygon( - shell, holes); - } - - private LinearRing[] getHoles(int n, double originX, double originY, double width) - { - List holeList = new ArrayList(); - - addHoles(n, originX, originY, width, holeList ); - - return GeometryFactory.toLinearRingArray(holeList); - } - - private void addHoles(int n, double originX, double originY, double width, List holeList) - { - if (n < 0) return; - int n2 = n - 1; - double widthThird = width / 3.0; - double widthTwoThirds = width * 2.0 / 3.0; - double widthNinth = width / 9.0; - addHoles(n2, originX, originY, widthThird, holeList); - addHoles(n2, originX + widthThird, originY, widthThird, holeList); - addHoles(n2, originX + 2 * widthThird, originY, widthThird, holeList); - - addHoles(n2, originX, originY + widthThird, widthThird, holeList); - addHoles(n2, originX + 2 * widthThird, originY + widthThird, widthThird, holeList); - - addHoles(n2, originX, originY + 2 * widthThird, widthThird, holeList); - addHoles(n2, originX + widthThird, originY + 2 * widthThird, widthThird, holeList); - addHoles(n2, originX + 2 * widthThird, originY + 2 * widthThird, widthThird, holeList); - - // add the centre hole - holeList.add(createSquareHole(originX + widthThird, originY + widthThird, widthThird)); - } - - private LinearRing createSquareHole(double x, double y, double width) - { - Coordinate[] pts = new Coordinate[]{ - new Coordinate(x, y), - new Coordinate(x + width, y), - new Coordinate(x + width, y + width), - new Coordinate(x, y + width), - new Coordinate(x, y) - } ; - return geomFactory.createLinearRing(pts); - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java b/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java deleted file mode 100644 index c6f6b9e434..0000000000 --- a/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java +++ /dev/null @@ -1,123 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.shape.random; - -import com.vividsolutions.jts.algorithm.locate.IndexedPointInAreaLocator; -import com.vividsolutions.jts.algorithm.locate.PointOnGeometryLocator; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.shape.GeometricShapeBuilder; - -/** - * Creates random point sets contained in a - * region defined by either a rectangular or a polygonal extent. - * - * @author mbdavis - * - */ -public class RandomPointsBuilder -extends GeometricShapeBuilder -{ - protected Geometry maskPoly = null; - private PointOnGeometryLocator extentLocator; - - /** - * Create a shape factory which will create shapes using the default - * {@link GeometryFactory}. - */ - public RandomPointsBuilder() - { - super(new GeometryFactory()); - } - - /** - * Create a shape factory which will create shapes using the given - * {@link GeometryFactory}. - * - * @param geomFact the factory to use - */ - public RandomPointsBuilder(GeometryFactory geomFact) - { - super(geomFact); - } - - /** - * Sets a polygonal mask. - * - * @param mask - * @throws IllegalArgumentException if the mask is not polygonal - */ - public void setExtent(Geometry mask) - { - if (! (mask instanceof Polygonal)) - throw new IllegalArgumentException("Only polygonal extents are supported"); - this.maskPoly = mask; - setExtent(mask.getEnvelopeInternal()); - extentLocator = new IndexedPointInAreaLocator(mask); - } - - public Geometry getGeometry() - { - Coordinate[] pts = new Coordinate[numPts]; - int i = 0; - while (i < numPts) { - Coordinate p = createRandomCoord(getExtent()); - if (extentLocator != null && ! isInExtent(p)) - continue; - pts[i++] = p; - } - return geomFactory.createMultiPoint(pts); - } - - protected boolean isInExtent(Coordinate p) - { - if (extentLocator != null) - return extentLocator.locate(p) != Location.EXTERIOR; - return getExtent().contains(p); - } - - protected Coordinate createCoord(double x, double y) - { - Coordinate pt = new Coordinate(x, y); - geomFactory.getPrecisionModel().makePrecise(pt); - return pt; - } - - protected Coordinate createRandomCoord(Envelope env) - { - double x = env.getMinX() + env.getWidth() * Math.random(); - double y = env.getMinY() + env.getHeight() * Math.random(); - return createCoord(x, y); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java b/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java deleted file mode 100644 index 25f86e207b..0000000000 --- a/src/main/java/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java +++ /dev/null @@ -1,173 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.shape.random; - -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.algorithm.locate.IndexedPointInAreaLocator; -import com.vividsolutions.jts.algorithm.locate.PointOnGeometryLocator; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.math.MathUtil; -import com.vividsolutions.jts.shape.GeometricShapeBuilder; - -/** - * Creates random point sets - * where the points are constrained to lie in the cells of a grid. - * - * @author mbdavis - * - */ -public class RandomPointsInGridBuilder -extends GeometricShapeBuilder -{ - private boolean isConstrainedToCircle = false; - private double gutterFraction = 0; - - /** - * Create a builder which will create shapes using the default - * {@link GeometryFactory}. - */ - public RandomPointsInGridBuilder() - { - super(new GeometryFactory()); - } - - /** - * Create a builder which will create shapes using the given - * {@link GeometryFactory}. - * - * @param geomFact the factory to use - */ - public RandomPointsInGridBuilder(GeometryFactory geomFact) - { - super(geomFact); - } - - /** - * Sets whether generated points are constrained to lie - * within a circle contained within each grid cell. - * This provides greater separation between points - * in adjacent cells. - *

                        - * The default is to not be constrained to a circle. - * @param isConstrainedToCircle - */ - public void setConstrainedToCircle(boolean isConstrainedToCircle) - { - this.isConstrainedToCircle = isConstrainedToCircle; - } - - /** - * Sets the fraction of the grid cell side which will be treated as - * a gutter, in which no points will be created. - * The provided value is clamped to the range [0.0, 1.0]. - * - * @param gutterFraction - */ - public void setGutterFraction(double gutterFraction) - { - this.gutterFraction = gutterFraction; - } - - /** - * Gets the {@link MultiPoint} containing the generated point - * - * @return a MultiPoint - */ - public Geometry getGeometry() - { - int nCells = (int) Math.sqrt(numPts); - // ensure that at least numPts points are generated - if (nCells * nCells < numPts) - nCells += 1; - - double gridDX = getExtent().getWidth() / nCells; - double gridDY = getExtent().getHeight() / nCells; - - double gutterFrac = MathUtil.clamp(gutterFraction, 0.0, 1.0); - double gutterOffsetX = gridDX * gutterFrac/2; - double gutterOffsetY = gridDY * gutterFrac/2; - double cellFrac = 1.0 - gutterFrac; - double cellDX = cellFrac * gridDX; - double cellDY = cellFrac * gridDY; - - Coordinate[] pts = new Coordinate[nCells * nCells]; - int index = 0; - for (int i = 0; i < nCells; i++) { - for (int j = 0; j < nCells; j++) { - double orgX = getExtent().getMinX() + i * gridDX + gutterOffsetX; - double orgY = getExtent().getMinY() + j * gridDY + gutterOffsetY; - pts[index++] = randomPointInCell(orgX, orgY, cellDX, cellDY); - } - } - return geomFactory.createMultiPoint(pts); - } - - private Coordinate randomPointInCell(double orgX, double orgY, double xLen, double yLen) - { - if (isConstrainedToCircle) { - return randomPointInCircle( - orgX, - orgY, - xLen, yLen); - } - return randomPointInGridCell(orgX, orgY, xLen, yLen); - } - - private Coordinate randomPointInGridCell(double orgX, double orgY, double xLen, double yLen) - { - double x = orgX + xLen * Math.random(); - double y = orgY + yLen * Math.random(); - return createCoord(x, y); - } - - private static Coordinate randomPointInCircle(double orgX, double orgY, double width, double height) - { - double centreX = orgX + width/2; - double centreY = orgY + height/2; - - double rndAng = 2 * Math.PI * Math.random(); - double rndRadius = Math.random(); - // use square root of radius, since area is proportional to square of radius - double rndRadius2 = Math.sqrt(rndRadius); - double rndX = width/2 * rndRadius2 * Math.cos(rndAng); - double rndY = height/2 * rndRadius2 * Math.sin(rndAng); - - double x0 = centreX + rndX; - double y0 = centreY + rndY; - return new Coordinate(x0, y0); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java deleted file mode 100644 index 63f63597a6..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java +++ /dev/null @@ -1,116 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import com.vividsolutions.jts.geom.*; - -/** - * Simplifies a linestring (sequence of points) using - * the standard Douglas-Peucker algorithm. - * - * @version 1.7 - */ -class DouglasPeuckerLineSimplifier -{ - public static Coordinate[] simplify(Coordinate[] pts, double distanceTolerance) - { - DouglasPeuckerLineSimplifier simp = new DouglasPeuckerLineSimplifier(pts); - simp.setDistanceTolerance(distanceTolerance); - return simp.simplify(); - } - - private Coordinate[] pts; - private boolean[] usePt; - private double distanceTolerance; - - public DouglasPeuckerLineSimplifier(Coordinate[] pts) - { - this.pts = pts; - } - /** - * Sets the distance tolerance for the simplification. - * All vertices in the simplified linestring will be within this - * distance of the original linestring. - * - * @param distanceTolerance the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - this.distanceTolerance = distanceTolerance; - } - - public Coordinate[] simplify() - { - usePt = new boolean[pts.length]; - for (int i = 0; i < pts.length; i++) { - usePt[i] = true; - } - simplifySection(0, pts.length - 1); - CoordinateList coordList = new CoordinateList(); - for (int i = 0; i < pts.length; i++) { - if (usePt[i]) - coordList.add(new Coordinate(pts[i])); - } - return coordList.toCoordinateArray(); - } - - private LineSegment seg = new LineSegment(); - - private void simplifySection(int i, int j) - { - if((i+1) == j) { - return; - } - seg.p0 = pts[i]; - seg.p1 = pts[j]; - double maxDistance = -1.0; - int maxIndex = i; - for (int k = i + 1; k < j; k++) { - double distance = seg.distance(pts[k]); - if (distance > maxDistance) { - maxDistance = distance; - maxIndex = k; - } - } - if (maxDistance <= distanceTolerance) { - for(int k = i + 1; k < j; k++) { - usePt[k] = false; - } - } - else { - simplifySection(i, maxIndex); - simplifySection(maxIndex, j); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java deleted file mode 100644 index 3c92a80df0..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java +++ /dev/null @@ -1,224 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Simplifies a {@link Geometry} using the Douglas-Peucker algorithm. - * Ensures that any polygonal geometries returned are valid. - * Simple lines are not guaranteed to remain simple after simplification. - * All geometry types are handled. - * Empty and point geometries are returned unchanged. - * Empty geometry components are deleted. - *

                        - * Note that in general D-P does not preserve topology - - * e.g. polygons can be split, collapse to lines or disappear - * holes can be created or disappear, - * and lines can cross. - * To simplify geometry while preserving topology use {@link TopologyPreservingSimplifier}. - * (However, using D-P is significantly faster). - *

                        KNOWN BUGS

                        - *
                          - *
                        • In some cases the approach used to clean invalid simplified polygons - *can distort the output geometry severely. - *
                        - * - * - * @version 1.7 - * @see TopologyPreservingSimplifier - */ -public class DouglasPeuckerSimplifier -{ - - /** - * Simplifies a geometry using a given tolerance. - * - * @param geom geometry to simplify - * @param distanceTolerance the tolerance to use - * @return a simplified version of the geometry - */ - public static Geometry simplify(Geometry geom, double distanceTolerance) - { - DouglasPeuckerSimplifier tss = new DouglasPeuckerSimplifier(geom); - tss.setDistanceTolerance(distanceTolerance); - return tss.getResultGeometry(); - } - - private Geometry inputGeom; - private double distanceTolerance; - private boolean isEnsureValidTopology = true; - - /** - * Creates a simplifier for a given geometry. - * - * @param inputGeom the geometry to simplify - */ - public DouglasPeuckerSimplifier(Geometry inputGeom) - { - this.inputGeom = inputGeom; - } - - /** - * Sets the distance tolerance for the simplification. - * All vertices in the simplified geometry will be within this - * distance of the original geometry. - * The tolerance value must be non-negative. - * - * @param distanceTolerance the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - if (distanceTolerance < 0.0) - throw new IllegalArgumentException("Tolerance must be non-negative"); - this.distanceTolerance = distanceTolerance; - } - - /** - * Controls whether simplified polygons will be "fixed" - * to have valid topology. - * The caller may choose to disable this because: - *
                          - *
                        • valid topology is not required - *
                        • fixing topology is a relative expensive operation - *
                        • in some pathological cases the topology fixing operation may either fail or run for too long - *
                        - * - * The default is to fix polygon topology. - * - * @param isEnsureValidTopology - */ - public void setEnsureValid(boolean isEnsureValidTopology) - { - this.isEnsureValidTopology = isEnsureValidTopology; - } - - /** - * Gets the simplified geometry. - * - * @return the simplified geometry - */ - public Geometry getResultGeometry() - { - // empty input produces an empty result - if (inputGeom.isEmpty()) return (Geometry) inputGeom.clone(); - - return (new DPTransformer(isEnsureValidTopology)).transform(inputGeom); - } - -class DPTransformer - extends GeometryTransformer -{ - private boolean isEnsureValidTopology = true; - - public DPTransformer(boolean isEnsureValidTopology) - { - this.isEnsureValidTopology = isEnsureValidTopology; - } - - protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) - { - Coordinate[] inputPts = coords.toCoordinateArray(); - Coordinate[] newPts = null; - if (inputPts.length == 0) { - newPts = new Coordinate[0]; - } - else { - newPts = DouglasPeuckerLineSimplifier.simplify(inputPts, distanceTolerance); - } - return factory.getCoordinateSequenceFactory().create(newPts); - } - - /** - * Simplifies a polygon, fixing it if required. - */ - protected Geometry transformPolygon(Polygon geom, Geometry parent) { - // empty geometries are simply removed - if (geom.isEmpty()) - return null; - Geometry rawGeom = super.transformPolygon(geom, parent); - // don't try and correct if the parent is going to do this - if (parent instanceof MultiPolygon) { - return rawGeom; - } - return createValidArea(rawGeom); - } - - /** - * Simplifies a LinearRing. If the simplification results - * in a degenerate ring, remove the component. - * - * @return null if the simplification results in a degenerate ring - */ - protected Geometry transformLinearRing(LinearRing geom, Geometry parent) - { - boolean removeDegenerateRings = parent instanceof Polygon; - Geometry simpResult = super.transformLinearRing(geom, parent); - if (removeDegenerateRings && ! (simpResult instanceof LinearRing)) - return null;; - return simpResult; - } - - /** - * Simplifies a MultiPolygon, fixing it if required. - */ - protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) { - Geometry rawGeom = super.transformMultiPolygon(geom, parent); - return createValidArea(rawGeom); - } - - /** - * Creates a valid area geometry from one that possibly has - * bad topology (i.e. self-intersections). - * Since buffer can handle invalid topology, but always returns - * valid geometry, constructing a 0-width buffer "corrects" the - * topology. - * Note this only works for area geometries, since buffer always returns - * areas. This also may return empty geometries, if the input - * has no actual area. - * - * @param rawAreaGeom an area geometry possibly containing self-intersections - * @return a valid area geometry - */ - private Geometry createValidArea(Geometry rawAreaGeom) - { - if ( isEnsureValidTopology) - return rawAreaGeom.buffer(0.0); - return rawAreaGeom; - } -} - -} - - diff --git a/src/main/java/com/vividsolutions/jts/simplify/LineSegmentIndex.java b/src/main/java/com/vividsolutions/jts/simplify/LineSegmentIndex.java deleted file mode 100644 index 6c520c3f0a..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/LineSegmentIndex.java +++ /dev/null @@ -1,113 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.index.*; -import com.vividsolutions.jts.index.quadtree.Quadtree; - -/** - * An spatial index on a set of {@link LineSegment}s. - * Supports adding and removing items. - * - * @author Martin Davis - */ -class LineSegmentIndex -{ - private Quadtree index = new Quadtree(); - - public LineSegmentIndex() - { - } - - public void add(TaggedLineString line) { - TaggedLineSegment[] segs = line.getSegments(); - for (int i = 0; i < segs.length; i++) { - TaggedLineSegment seg = segs[i]; - add(seg); - } - } - - public void add(LineSegment seg) - { - index.insert(new Envelope(seg.p0, seg.p1), seg); - } - - public void remove(LineSegment seg) - { - index.remove(new Envelope(seg.p0, seg.p1), seg); - } - - public List query(LineSegment querySeg) - { - Envelope env = new Envelope(querySeg.p0, querySeg.p1); - - LineSegmentVisitor visitor = new LineSegmentVisitor(querySeg); - index.query(env, visitor); - List itemsFound = visitor.getItems(); - -// List listQueryItems = index.query(env); -// System.out.println("visitor size = " + itemsFound.size() -// + " query size = " + listQueryItems.size()); -// List itemsFound = index.query(env); - - return itemsFound; - } -} - -/** - * ItemVisitor subclass to reduce volume of query results. - */ -class LineSegmentVisitor - implements ItemVisitor -{ -// MD - only seems to make about a 10% difference in overall time. - - private LineSegment querySeg; - private ArrayList items = new ArrayList(); - - public LineSegmentVisitor(LineSegment querySeg) { - this.querySeg = querySeg; - } - - public void visitItem(Object item) - { - LineSegment seg = (LineSegment) item; - if (Envelope.intersects(seg.p0, seg.p1, querySeg.p0, querySeg.p1)) - items.add(item); - } - - public ArrayList getItems() { return items; } -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineSegment.java b/src/main/java/com/vividsolutions/jts/simplify/TaggedLineSegment.java deleted file mode 100644 index 2e2ca0fa3a..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineSegment.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import com.vividsolutions.jts.geom.*; - -/** - * A {@link LineSegment} which is tagged with its location in a parent {@link Geometry}. - * Used to index the segments in a geometry and recover the segment locations - * from the index. - */ -class TaggedLineSegment - extends LineSegment -{ - private Geometry parent; - private int index; - - public TaggedLineSegment(Coordinate p0, Coordinate p1, Geometry parent, int index) { - super(p0, p1); - this.parent = parent; - this.index = index; - } - - public TaggedLineSegment(Coordinate p0, Coordinate p1) { - this(p0, p1, null, -1); - } - - public Geometry getParent() { return parent; } - public int getIndex() { return index; } -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineString.java b/src/main/java/com/vividsolutions/jts/simplify/TaggedLineString.java deleted file mode 100644 index d748907e9d..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineString.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Represents a {@link LineString} which can be modified to a simplified shape. - * This class provides an attribute which specifies the minimum allowable length - * for the modified result. - * - * @version 1.7 - */ -class TaggedLineString -{ - - private LineString parentLine; - private TaggedLineSegment[] segs; - private List resultSegs = new ArrayList(); - private int minimumSize; - - public TaggedLineString(LineString parentLine) { - this(parentLine, 2); - } - - public TaggedLineString(LineString parentLine, int minimumSize) { - this.parentLine = parentLine; - this.minimumSize = minimumSize; - init(); - } - - public int getMinimumSize() { return minimumSize; } - public LineString getParent() { return parentLine; } - public Coordinate[] getParentCoordinates() { return parentLine.getCoordinates(); } - public Coordinate[] getResultCoordinates() { return extractCoordinates(resultSegs); } - - public int getResultSize() - { - int resultSegsSize = resultSegs.size(); - return resultSegsSize == 0 ? 0 : resultSegsSize + 1; - } - - public TaggedLineSegment getSegment(int i) { return segs[i]; } - - private void init() - { - Coordinate[] pts = parentLine.getCoordinates(); - segs = new TaggedLineSegment[pts.length - 1]; - for (int i = 0; i < pts.length - 1; i++) { - TaggedLineSegment seg - = new TaggedLineSegment(pts[i], pts[i + 1], parentLine, i); - segs[i] = seg; - } - } - - public TaggedLineSegment[] getSegments() { return segs; } - - public void addToResult(LineSegment seg) - { - resultSegs.add(seg); - } - - public LineString asLineString() - { - return parentLine.getFactory().createLineString(extractCoordinates(resultSegs)); - } - - public LinearRing asLinearRing() { - return parentLine.getFactory().createLinearRing(extractCoordinates(resultSegs)); - } - - private static Coordinate[] extractCoordinates(List segs) - { - Coordinate[] pts = new Coordinate[segs.size() + 1]; - LineSegment seg = null; - for (int i = 0; i < segs.size(); i++) { - seg = (LineSegment) segs.get(i); - pts[i] = seg.p0; - } - // add last point - pts[pts.length - 1] = seg.p1; - return pts; - } - - -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java deleted file mode 100644 index e06ad2626f..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java +++ /dev/null @@ -1,256 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import java.util.*; -import com.vividsolutions.jts.algorithm.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.util.Debug; - -/** - * Simplifies a TaggedLineString, preserving topology - * (in the sense that no new intersections are introduced). - * Uses the recursive Douglas-Peucker algorithm. - * - * @author Martin Davis - * @version 1.7 - */ -public class TaggedLineStringSimplifier -{ - private LineIntersector li = new RobustLineIntersector(); - private LineSegmentIndex inputIndex = new LineSegmentIndex(); - private LineSegmentIndex outputIndex = new LineSegmentIndex(); - private TaggedLineString line; - private Coordinate[] linePts; - private double distanceTolerance = 0.0; - - public TaggedLineStringSimplifier(LineSegmentIndex inputIndex, - LineSegmentIndex outputIndex) - { - this.inputIndex = inputIndex; - this.outputIndex = outputIndex; - } - - /** - * Sets the distance tolerance for the simplification. - * All vertices in the simplified geometry will be within this - * distance of the original geometry. - * - * @param distanceTolerance the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - this.distanceTolerance = distanceTolerance; - } - - /** - * Simplifies the given {@link TaggedLineString} - * using the distance tolerance specified. - * - * @param line the linestring to simplify - */ - void simplify(TaggedLineString line) - { - this.line = line; - linePts = line.getParentCoordinates(); - simplifySection(0, linePts.length - 1, 0); - } - - private void simplifySection(int i, int j, int depth) - { - depth += 1; - int[] sectionIndex = new int[2]; - if((i+1) == j) { - LineSegment newSeg = line.getSegment(i); - line.addToResult(newSeg); - // leave this segment in the input index, for efficiency - return; - } - - boolean isValidToSimplify = true; - - /** - * Following logic ensures that there is enough points in the output line. - * If there is already more points than the minimum, there's nothing to check. - * Otherwise, if in the worst case there wouldn't be enough points, - * don't flatten this segment (which avoids the worst case scenario) - */ - if (line.getResultSize() < line.getMinimumSize()) { - int worstCaseSize = depth + 1; - if (worstCaseSize < line.getMinimumSize()) - isValidToSimplify = false; - } - - double[] distance = new double[1]; - int furthestPtIndex = findFurthestPoint(linePts, i, j, distance); - // flattening must be less than distanceTolerance - if (distance[0] > distanceTolerance) isValidToSimplify = false; - // test if flattened section would cause intersection - LineSegment candidateSeg = new LineSegment(); - candidateSeg.p0 = linePts[i]; - candidateSeg.p1 = linePts[j]; - sectionIndex[0] = i; - sectionIndex[1] = j; - if (hasBadIntersection(line, sectionIndex, candidateSeg)) isValidToSimplify = false; - - if (isValidToSimplify) { - LineSegment newSeg = flatten(i, j); - line.addToResult(newSeg); - return; - } - simplifySection(i, furthestPtIndex, depth); - simplifySection(furthestPtIndex, j, depth); - } - - private int findFurthestPoint(Coordinate[] pts, int i, int j, double[] maxDistance) - { - LineSegment seg = new LineSegment(); - seg.p0 = pts[i]; - seg.p1 = pts[j]; - double maxDist = -1.0; - int maxIndex = i; - for (int k = i + 1; k < j; k++) { - Coordinate midPt = pts[k]; - double distance = seg.distance(midPt); - if (distance > maxDist) { - maxDist = distance; - maxIndex = k; - } - } - maxDistance[0] = maxDist; - return maxIndex; - } - - /** - * Flattens a section of the line between - * indexes start and end, - * replacing them with a line between the endpoints. - * The input and output indexes are updated - * to reflect this. - * - * @param start the start index of the flattened section - * @param end the end index of the flattened section - * @return the new segment created - */ - private LineSegment flatten(int start, int end) - { - // make a new segment for the simplified geometry - Coordinate p0 = linePts[start]; - Coordinate p1 = linePts[end]; - LineSegment newSeg = new LineSegment(p0, p1); - // update the indexes - remove(line, start, end); - outputIndex.add(newSeg); - return newSeg; - } - - private boolean hasBadIntersection(TaggedLineString parentLine, - int[] sectionIndex, - LineSegment candidateSeg) - { - if (hasBadOutputIntersection(candidateSeg)) return true; - if (hasBadInputIntersection(parentLine, sectionIndex, candidateSeg)) return true; - return false; - } - - private boolean hasBadOutputIntersection(LineSegment candidateSeg) - { - List querySegs = outputIndex.query(candidateSeg); - for (Iterator i = querySegs.iterator(); i.hasNext(); ) { - LineSegment querySeg = (LineSegment) i.next(); - if (hasInteriorIntersection(querySeg, candidateSeg)) { - return true; - } - } - return false; - } - - private boolean hasBadInputIntersection(TaggedLineString parentLine, - int[] sectionIndex, - LineSegment candidateSeg) - { - List querySegs = inputIndex.query(candidateSeg); - for (Iterator i = querySegs.iterator(); i.hasNext(); ) { - TaggedLineSegment querySeg = (TaggedLineSegment) i.next(); - if (hasInteriorIntersection(querySeg, candidateSeg)) { - if (isInLineSection(parentLine, sectionIndex, querySeg)) - continue; - return true; - } - } - return false; - } - - /** - * Tests whether a segment is in a section of a TaggedLineString - * @param line - * @param sectionIndex - * @param seg - * @return - */ - private static boolean isInLineSection( - TaggedLineString line, - int[] sectionIndex, - TaggedLineSegment seg) - { - // not in this line - if (seg.getParent() != line.getParent()) - return false; - int segIndex = seg.getIndex(); - if (segIndex >= sectionIndex[0] && segIndex < sectionIndex[1]) - return true; - return false; - } - - private boolean hasInteriorIntersection(LineSegment seg0, LineSegment seg1) - { - li.computeIntersection(seg0.p0, seg0.p1, seg1.p0, seg1.p1); - return li.isInteriorIntersection(); - } - - /** - * Remove the segs in the section of the line - * @param line - * @param pts - * @param sectionStartIndex - * @param sectionEndIndex - */ - private void remove(TaggedLineString line, - int start, int end) - { - for (int i = start; i < end; i++) { - TaggedLineSegment seg = line.getSegment(i); - inputIndex.remove(seg); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java deleted file mode 100644 index 7d99368911..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java +++ /dev/null @@ -1,84 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import java.util.Collection; -import java.util.Iterator; - -/** - * Simplifies a collection of TaggedLineStrings, preserving topology - * (in the sense that no new intersections are introduced). - * This class is essentially just a container for the common - * indexes used by {@link TaggedLineStringSimplifier}. - */ -class TaggedLinesSimplifier -{ - private LineSegmentIndex inputIndex = new LineSegmentIndex(); - private LineSegmentIndex outputIndex = new LineSegmentIndex(); - private double distanceTolerance = 0.0; - - public TaggedLinesSimplifier() - { - - } - - /** - * Sets the distance tolerance for the simplification. - * All vertices in the simplified geometry will be within this - * distance of the original geometry. - * - * @param distanceTolerance the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - this.distanceTolerance = distanceTolerance; - } - - /** - * Simplify a collection of TaggedLineStrings - * - * @param taggedLines the collection of lines to simplify - */ - public void simplify(Collection taggedLines) { - for (Iterator i = taggedLines.iterator(); i.hasNext(); ) { - inputIndex.add((TaggedLineString) i.next()); - } - for (Iterator i = taggedLines.iterator(); i.hasNext(); ) { - TaggedLineStringSimplifier tlss - = new TaggedLineStringSimplifier(inputIndex, outputIndex); - tlss.setDistanceTolerance(distanceTolerance); - tlss.simplify((TaggedLineString) i.next()); - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java deleted file mode 100644 index 87e626c2d5..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java +++ /dev/null @@ -1,187 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.simplify; - -import java.util.*; -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.util.Debug; - -/** - * Simplifies a geometry and ensures that - * the result is a valid geometry having the - * same dimension and number of components as the input, - * and with the components having the same topological - * relationship. - *

                        - * If the input is a polygonal geometry - * ( {@link Polygon} or {@link MultiPolygon} ): - *

                          - *
                        • The result has the same number of shells and holes as the input, - * with the same topological structure - *
                        • The result rings touch at no more than the number of touching points in the input - * (although they may touch at fewer points). - * The key implication of this statement is that if the - * input is topologically valid, so is the simplified output. - *
                        - * For linear geometries, if the input does not contain - * any intersecting line segments, this property - * will be preserved in the output. - *

                        - * For all geometry types, the result will contain - * enough vertices to ensure validity. For polygons - * and closed linear geometries, the result will have at - * least 4 vertices; for open linestrings the result - * will have at least 2 vertices. - *

                        - * All geometry types are handled. - * Empty and point geometries are returned unchanged. - * Empty geometry components are deleted. - *

                        - * The simplification uses a maximum-distance difference algorithm - * similar to the Douglas-Peucker algorithm. - * - *

                        KNOWN BUGS

                        - *
                          - *
                        • May create invalid topology if there are components which are - * small relative to the tolerance value. - * In particular, if a small hole is very near an edge, it is possible for the edge to be moved by - * a relatively large tolerance value and end up with the hole outside the result shell - * (or inside another hole). - * Similarly, it is possible for a small polygon component to end up inside - * a nearby larger polygon. - * A workaround is to test for this situation in post-processing and remove - * any invalid holes or polygons. - *
                        - * - * @author Martin Davis - * @see DouglasPeuckerSimplifier - * - */ -public class TopologyPreservingSimplifier -{ - public static Geometry simplify(Geometry geom, double distanceTolerance) - { - TopologyPreservingSimplifier tss = new TopologyPreservingSimplifier(geom); - tss.setDistanceTolerance(distanceTolerance); - return tss.getResultGeometry(); - } - - private Geometry inputGeom; - private TaggedLinesSimplifier lineSimplifier = new TaggedLinesSimplifier(); - private Map linestringMap; - - public TopologyPreservingSimplifier(Geometry inputGeom) - { - this.inputGeom = inputGeom; - } - - /** - * Sets the distance tolerance for the simplification. - * All vertices in the simplified geometry will be within this - * distance of the original geometry. - * The tolerance value must be non-negative. A tolerance value - * of zero is effectively a no-op. - * - * @param distanceTolerance the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) { - if (distanceTolerance < 0.0) - throw new IllegalArgumentException("Tolerance must be non-negative"); - lineSimplifier.setDistanceTolerance(distanceTolerance); - } - - public Geometry getResultGeometry() - { - // empty input produces an empty result - if (inputGeom.isEmpty()) return (Geometry) inputGeom.clone(); - - linestringMap = new HashMap(); - inputGeom.apply(new LineStringMapBuilderFilter()); - lineSimplifier.simplify(linestringMap.values()); - Geometry result = (new LineStringTransformer()).transform(inputGeom); - return result; - } - - class LineStringTransformer - extends GeometryTransformer - { - protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) - { - if (coords.size() == 0) return null; - // for linear components (including rings), simplify the linestring - if (parent instanceof LineString) { - TaggedLineString taggedLine = (TaggedLineString) linestringMap.get(parent); - return createCoordinateSequence(taggedLine.getResultCoordinates()); - } - // for anything else (e.g. points) just copy the coordinates - return super.transformCoordinates(coords, parent); - } - } - - /** - * A filter to add linear geometries to the linestring map - * with the appropriate minimum size constraint. - * Closed {@link LineString}s (including {@link LinearRing}s - * have a minimum output size constraint of 4, - * to ensure the output is valid. - * For all other linestrings, the minimum size is 2 points. - * - * @author Martin Davis - * - */ - class LineStringMapBuilderFilter - implements GeometryComponentFilter - { - /** - * Filters linear geometries. - * - * geom a geometry of any type - */ - public void filter(Geometry geom) - { - if (geom instanceof LineString) { - LineString line = (LineString) geom; - // skip empty geometries - if (line.isEmpty()) return; - - int minSize = ((LineString) line).isClosed() ? 4 : 2; - TaggedLineString taggedLine = new TaggedLineString((LineString) line, minSize); - linestringMap.put(line, taggedLine); - } - } - } - -} - diff --git a/src/main/java/com/vividsolutions/jts/simplify/VWLineSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/VWLineSimplifier.java deleted file mode 100644 index 38679faa2a..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/VWLineSimplifier.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.vividsolutions.jts.simplify; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateList; -import com.vividsolutions.jts.geom.Triangle; - -/** - * Simplifies a linestring (sequence of points) using the - * Visvalingam-Whyatt algorithm. - * The Visvalingam-Whyatt algorithm simplifies geometry - * by removing vertices while trying to minimize the area changed. - * - * @version 1.7 - */ -class VWLineSimplifier -{ - public static Coordinate[] simplify(Coordinate[] pts, double distanceTolerance) - { - VWLineSimplifier simp = new VWLineSimplifier(pts, distanceTolerance); - return simp.simplify(); - } - - private Coordinate[] pts; - private double tolerance; - - public VWLineSimplifier(Coordinate[] pts, double distanceTolerance) - { - this.pts = pts; - this.tolerance = distanceTolerance * distanceTolerance; - } - - public Coordinate[] simplify() - { - VWLineSimplifier.VWVertex vwLine = VWVertex.buildLine(pts); - double minArea = tolerance; - do { - minArea = simplifyVertex(vwLine); - } while (minArea < tolerance); - Coordinate[] simp = vwLine.getCoordinates(); - // ensure computed value is a valid line - if (simp.length < 2) { - return new Coordinate[] { simp[0], new Coordinate(simp[0]) }; - } - return simp; - } - - private double simplifyVertex(VWLineSimplifier.VWVertex vwLine) - { - /** - * Scan vertices in line and remove the one with smallest effective area. - */ - // TODO: use an appropriate data structure to optimize finding the smallest area vertex - VWLineSimplifier.VWVertex curr = vwLine; - double minArea = curr.getArea(); - VWLineSimplifier.VWVertex minVertex = null; - while (curr != null) { - double area = curr.getArea(); - if (area < minArea) { - minArea = area; - minVertex = curr; - } - curr = curr.next; - } - if (minVertex != null && minArea < tolerance) { - minVertex.remove(); - } - if (! vwLine.isLive()) return -1; - return minArea; - } - - - static class VWVertex - { - public static VWLineSimplifier.VWVertex buildLine(Coordinate[] pts) - { - VWLineSimplifier.VWVertex first = null; - VWLineSimplifier.VWVertex prev = null; - for (int i = 0; i < pts.length; i++) { - VWLineSimplifier.VWVertex v = new VWVertex(pts[i]); - if (first == null) - first = v; - v.setPrev(prev); - if (prev != null) { - prev.setNext(v); - prev.updateArea(); - } - prev = v; - } - return first; - } - - public static double MAX_AREA = Double.MAX_VALUE; - - private Coordinate pt; - private VWLineSimplifier.VWVertex prev; - private VWLineSimplifier.VWVertex next; - private double area = MAX_AREA; - private boolean isLive = true; - - public VWVertex(Coordinate pt) - { - this.pt = pt; - } - - public void setPrev(VWLineSimplifier.VWVertex prev) - { - this.prev = prev; - } - - public void setNext(VWLineSimplifier.VWVertex next) - { - this.next = next; - } - - public void updateArea() - { - if (prev == null || next == null) { - area = MAX_AREA; - return; - } - area = Math.abs(Triangle.area(prev.pt, pt, next.pt)); - } - - public double getArea() - { - return area; - } - public boolean isLive() - { - return isLive; - } - public VWLineSimplifier.VWVertex remove() - { - VWLineSimplifier.VWVertex tmpPrev = prev; - VWLineSimplifier.VWVertex tmpNext = next; - VWLineSimplifier.VWVertex result = null; - if (prev != null) { - prev.setNext(tmpNext); - prev.updateArea(); - result = prev; - } - if (next != null) { - next.setPrev(tmpPrev); - next.updateArea(); - if (result == null) - result = next; - } - isLive = false; - return result; - } - public Coordinate[] getCoordinates() - { - CoordinateList coords = new CoordinateList(); - VWLineSimplifier.VWVertex curr = this; - do { - coords.add(curr.pt, false); - curr = curr.next; - } while (curr != null); - return coords.toCoordinateArray(); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/simplify/VWSimplifier.java b/src/main/java/com/vividsolutions/jts/simplify/VWSimplifier.java deleted file mode 100644 index 78e7183a75..0000000000 --- a/src/main/java/com/vividsolutions/jts/simplify/VWSimplifier.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.simplify; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; - -/** - * Simplifies a {@link Geometry} using the Visvalingam-Whyatt area-based algorithm. - * Ensures that any polygonal geometries returned are valid. Simple lines are not - * guaranteed to remain simple after simplification. All geometry types are - * handled. Empty and point geometries are returned unchanged. Empty geometry - * components are deleted. - *

                        - * The simplification tolerance is specified as a distance. - * This is converted to an area tolerance by squaring it. - *

                        - * Note that in general this algorithm does not preserve topology - e.g. polygons can be split, - * collapse to lines or disappear holes can be created or disappear, and lines - * can cross. - * - *

                        Known Bugs

                        - *
                          - *
                        • Not yet optimized for performance - *
                        • Does not simplify the endpoint of rings - *
                        - *

                        To Do

                        - *
                          - *
                        • Allow specifying desired number of vertices in the output - *
                        - * - * @version 1.7 - */ -public class VWSimplifier -{ - - /** - * Simplifies a geometry using a given tolerance. - * - * @param geom geometry to simplify - * @param distanceTolerance the tolerance to use - * @return a simplified version of the geometry - */ - public static Geometry simplify(Geometry geom, double distanceTolerance) - { - VWSimplifier simp = new VWSimplifier(geom); - simp.setDistanceTolerance(distanceTolerance); - return simp.getResultGeometry(); - } - - private Geometry inputGeom; - private double distanceTolerance; - private boolean isEnsureValidTopology = true; - - /** - * Creates a simplifier for a given geometry. - * - * @param inputGeom the geometry to simplify - */ - public VWSimplifier(Geometry inputGeom) - { - this.inputGeom = inputGeom; - } - - /** - * Sets the distance tolerance for the simplification. All vertices in the - * simplified geometry will be within this distance of the original geometry. - * The tolerance value must be non-negative. - * - * @param distanceTolerance - * the approximation tolerance to use - */ - public void setDistanceTolerance(double distanceTolerance) - { - if (distanceTolerance < 0.0) - throw new IllegalArgumentException("Tolerance must be non-negative"); - this.distanceTolerance = distanceTolerance; - } - - /** - * Controls whether simplified polygons will be "fixed" to have valid - * topology. The caller may choose to disable this because: - *
                          - *
                        • valid topology is not required - *
                        • fixing topology is a relative expensive operation - *
                        • in some pathological cases the topology fixing operation may either - * fail or run for too long - *
                        - * - * The default is to fix polygon topology. - * - * @param isEnsureValidTopology - */ - public void setEnsureValid(boolean isEnsureValidTopology) - { - this.isEnsureValidTopology = isEnsureValidTopology; - } - - /** - * Gets the simplified geometry. - * - * @return the simplified geometry - */ - public Geometry getResultGeometry() - { - // empty input produces an empty result - if (inputGeom.isEmpty()) - return (Geometry) inputGeom.clone(); - - return (new VWTransformer(isEnsureValidTopology)).transform(inputGeom); - } - - class VWTransformer extends GeometryTransformer - { - private boolean isEnsureValidTopology = true; - - public VWTransformer(boolean isEnsureValidTopology) - { - this.isEnsureValidTopology = isEnsureValidTopology; - } - - protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent) - { - Coordinate[] inputPts = coords.toCoordinateArray(); - Coordinate[] newPts = null; - if (inputPts.length == 0) { - newPts = new Coordinate[0]; - } - else { - newPts = VWLineSimplifier.simplify(inputPts, distanceTolerance); - } - return factory.getCoordinateSequenceFactory().create(newPts); - } - - /** - * Simplifies a polygon, fixing it if required. - */ - protected Geometry transformPolygon(Polygon geom, Geometry parent) - { - // empty geometries are simply removed - if (geom.isEmpty()) - return null; - Geometry rawGeom = super.transformPolygon(geom, parent); - // don't try and correct if the parent is going to do this - if (parent instanceof MultiPolygon) { - return rawGeom; - } - return createValidArea(rawGeom); - } - - /** - * Simplifies a LinearRing. If the simplification results in a degenerate - * ring, remove the component. - * - * @return null if the simplification results in a degenerate ring - */ - protected Geometry transformLinearRing(LinearRing geom, Geometry parent) - { - boolean removeDegenerateRings = parent instanceof Polygon; - Geometry simpResult = super.transformLinearRing(geom, parent); - if (removeDegenerateRings && !(simpResult instanceof LinearRing)) - return null; - ; - return simpResult; - } - - /** - * Simplifies a MultiPolygon, fixing it if required. - */ - protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) - { - Geometry rawGeom = super.transformMultiPolygon(geom, parent); - return createValidArea(rawGeom); - } - - /** - * Creates a valid area geometry from one that possibly has bad topology - * (i.e. self-intersections). Since buffer can handle invalid topology, but - * always returns valid geometry, constructing a 0-width buffer "corrects" - * the topology. Note this only works for area geometries, since buffer - * always returns areas. This also may return empty geometries, if the input - * has no actual area. - * - * @param rawAreaGeom - * an area geometry possibly containing self-intersections - * @return a valid area geometry - */ - private Geometry createValidArea(Geometry rawAreaGeom) - { - if (isEnsureValidTopology) - return rawAreaGeom.buffer(0.0); - return rawAreaGeom; - } - } - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulationBuilder.java b/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulationBuilder.java deleted file mode 100644 index 9c7067548d..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulationBuilder.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.triangulate; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.*; -import com.vividsolutions.jts.triangulate.quadedge.*; - -/** - * A utility class which creates Conforming Delaunay Trianglulations - * from collections of points and linear constraints, and extract the resulting - * triangulation edges or triangles as geometries. - * - * @author Martin Davis - * - */ -public class ConformingDelaunayTriangulationBuilder -{ - private Collection siteCoords; - private Geometry constraintLines; - private double tolerance = 0.0; - private QuadEdgeSubdivision subdiv = null; - - private Map constraintVertexMap = new TreeMap(); - - public ConformingDelaunayTriangulationBuilder() - { - } - - /** - * Sets the sites (point or vertices) which will be triangulated. - * All vertices of the given geometry will be used as sites. - * The site vertices do not have to contain the constraint - * vertices as well; any site vertices which are - * identical to a constraint vertex will be removed - * from the site vertex set. - * - * @param geom the geometry from which the sites will be extracted. - */ - public void setSites(Geometry geom) - { - siteCoords = DelaunayTriangulationBuilder.extractUniqueCoordinates(geom); - } - - /** - * Sets the linear constraints to be conformed to. - * All linear components in the input will be used as constraints. - * The constraint vertices do not have to be disjoint from - * the site vertices. - * The constraints must not contain duplicate segments (up to orientation). - * - * @param constraintLines the lines to constraint to - */ - public void setConstraints(Geometry constraintLines) - { - this.constraintLines = constraintLines; - } - - /** - * Sets the snapping tolerance which will be used - * to improved the robustness of the triangulation computation. - * A tolerance of 0.0 specifies that no snapping will take place. - * - * @param tolerance the tolerance distance to use - */ - public void setTolerance(double tolerance) - { - this.tolerance = tolerance; - } - - - private void create() - { - if (subdiv != null) return; - - Envelope siteEnv = DelaunayTriangulationBuilder.envelope(siteCoords); - - List segments = new ArrayList(); - if (constraintLines != null) { - siteEnv.expandToInclude(constraintLines.getEnvelopeInternal()); - createVertices(constraintLines); - segments = createConstraintSegments(constraintLines); - } - List sites = createSiteVertices(siteCoords); - - ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(sites, tolerance); - - cdt.setConstraints(segments, new ArrayList(constraintVertexMap.values())); - - cdt.formInitialDelaunay(); - cdt.enforceConstraints(); - subdiv = cdt.getSubdivision(); - } - - private List createSiteVertices(Collection coords) - { - List verts = new ArrayList(); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate coord = (Coordinate) i.next(); - if (constraintVertexMap.containsKey(coord)) - continue; - verts.add(new ConstraintVertex(coord)); - } - return verts; - } - - private void createVertices(Geometry geom) - { - Coordinate[] coords = geom.getCoordinates(); - for (int i = 0; i < coords.length; i++) { - Vertex v = new ConstraintVertex(coords[i]); - constraintVertexMap.put(coords[i], v); - } - } - - private static List createConstraintSegments(Geometry geom) - { - List lines = LinearComponentExtracter.getLines(geom); - List constraintSegs = new ArrayList(); - for (Iterator i = lines.iterator(); i.hasNext(); ) { - LineString line = (LineString) i.next(); - createConstraintSegments(line, constraintSegs); - } - return constraintSegs; - } - - private static void createConstraintSegments(LineString line, List constraintSegs) - { - Coordinate[] coords = line.getCoordinates(); - for (int i = 1; i < coords.length; i++) { - constraintSegs.add(new Segment(coords[i-1], coords[i])); - } - } - - /** - * Gets the QuadEdgeSubdivision which models the computed triangulation. - * - * @return the subdivision containing the triangulation - */ - public QuadEdgeSubdivision getSubdivision() - { - create(); - return subdiv; - } - - /** - * Gets the edges of the computed triangulation as a {@link MultiLineString}. - * - * @param geomFact the geometry factory to use to create the output - * @return the edges of the triangulation - */ - public Geometry getEdges(GeometryFactory geomFact) - { - create(); - return subdiv.getEdges(geomFact); - } - - /** - * Gets the faces of the computed triangulation as a {@link GeometryCollection} - * of {@link Polygon}. - * - * @param geomFact the geometry factory to use to create the output - * @return the faces of the triangulation - */ - public Geometry getTriangles(GeometryFactory geomFact) - { - create(); - return subdiv.getTriangles(geomFact); - } - -} - - diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulator.java b/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulator.java deleted file mode 100644 index 519ffcefff..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConformingDelaunayTriangulator.java +++ /dev/null @@ -1,564 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.vividsolutions.jts.algorithm.ConvexHull; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.util.Debug; -import com.vividsolutions.jts.index.kdtree.KdNode; -import com.vividsolutions.jts.index.kdtree.KdTree; -import com.vividsolutions.jts.triangulate.quadedge.LastFoundQuadEdgeLocator; -import com.vividsolutions.jts.triangulate.quadedge.QuadEdgeSubdivision; -import com.vividsolutions.jts.triangulate.quadedge.Vertex; - -/** - * Computes a Conforming Delaunay Triangulation over a set of sites and a set of - * linear constraints. - *

                        - * A conforming Delaunay triangulation is a true Delaunay triangulation. In it - * each constraint segment is present as a union of one or more triangulation - * edges. Constraint segments may be subdivided into two or more triangulation - * edges by the insertion of additional sites. The additional sites are called - * Steiner points, and are necessary to allow the segments to be faithfully - * reflected in the triangulation while maintaining the Delaunay property. - * Another way of stating this is that in a conforming Delaunay triangulation - * every constraint segment will be the union of a subset of the triangulation - * edges (up to tolerance). - *

                        - * A Conforming Delaunay triangulation is distinct from a Constrained Delaunay triangulation. - * A Constrained Delaunay triangulation is not necessarily fully Delaunay, - * and it contains the constraint segments exactly as edges of the triangulation. - *

                        - * A typical usage pattern for the triangulator is: - *

                        - * 	 ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(sites, tolerance);
                        - * 
                        - *   // optional	
                        - *   cdt.setSplitPointFinder(splitPointFinder);
                        - *   cdt.setVertexFactory(vertexFactory);
                        - *   
                        - *	 cdt.setConstraints(segments, new ArrayList(vertexMap.values()));
                        - *	 cdt.formInitialDelaunay();
                        - *	 cdt.enforceConstraints();
                        - *	 subdiv = cdt.getSubdivision();
                        - * 
                        - * - * @author David Skea - * @author Martin Davis - */ -public class ConformingDelaunayTriangulator -{ - private static Envelope computeVertexEnvelope(Collection vertices) { - Envelope env = new Envelope(); - for (Iterator i = vertices.iterator(); i.hasNext();) { - Vertex v = (Vertex) i.next(); - env.expandToInclude(v.getCoordinate()); - } - return env; - } - - private List initialVertices; // List - private List segVertices; // List - - // MD - using a Set doesn't seem to be much faster - // private Set segments = new HashSet(); - private List segments = new ArrayList(); // List - private QuadEdgeSubdivision subdiv = null; - private IncrementalDelaunayTriangulator incDel; - private Geometry convexHull; - private ConstraintSplitPointFinder splitFinder = new NonEncroachingSplitPointFinder(); - private KdTree kdt = null; - private ConstraintVertexFactory vertexFactory = null; - - // allPointsEnv expanded by a small buffer - private Envelope computeAreaEnv; - // records the last split point computed, for error reporting - private Coordinate splitPt = null; - - private double tolerance; // defines if two sites are the same. - - /** - * Creates a Conforming Delaunay Triangulation based on the given - * unconstrained initial vertices. The initial vertex set should not contain - * any vertices which appear in the constraint set. - * - * @param initialVertices - * a collection of {@link ConstraintVertex} - * @param tolerance - * the distance tolerance below which points are considered identical - */ - public ConformingDelaunayTriangulator(Collection initialVertices, - double tolerance) { - this.initialVertices = new ArrayList(initialVertices); - this.tolerance = tolerance; - kdt = new KdTree(tolerance); - } - - /** - * Sets the constraints to be conformed to by the computed triangulation. - * The constraints must not contain duplicate segments (up to orientation). - * The unique set of vertices (as {@link ConstraintVertex}es) - * forming the constraints must also be supplied. - * Supplying it explicitly allows the ConstraintVertexes to be initialized - * appropriately(e.g. with external data), and avoids re-computing the unique set - * if it is already available. - * - * @param segments a list of the constraint {@link Segment}s - * @param segVertices the set of unique {@link ConstraintVertex}es referenced by the segments - */ - public void setConstraints(List segments, List segVertices) { - this.segments = segments; - this.segVertices = segVertices; - } - - /** - * Sets the {@link ConstraintSplitPointFinder} to be - * used during constraint enforcement. - * Different splitting strategies may be appropriate - * for special situations. - * - * @param splitFinder the ConstraintSplitPointFinder to be used - */ - public void setSplitPointFinder(ConstraintSplitPointFinder splitFinder) { - this.splitFinder = splitFinder; - } - - /** - * Gets the tolerance value used to construct the triangulation. - * - * @return a tolerance value - */ - public double getTolerance() - { - return tolerance; - } - - /** - * Gets the ConstraintVertexFactory used to create new constraint vertices at split points. - * - * @return a new constraint vertex - */ - public ConstraintVertexFactory getVertexFactory() { - return vertexFactory; - } - - /** - * Sets a custom {@link ConstraintVertexFactory} to be used - * to allow vertices carrying extra information to be created. - * - * @param vertexFactory the ConstraintVertexFactory to be used - */ - public void setVertexFactory(ConstraintVertexFactory vertexFactory) { - this.vertexFactory = vertexFactory; - } - - /** - * Gets the {@link QuadEdgeSubdivision} which represents the triangulation. - * - * @return a subdivision - */ - public QuadEdgeSubdivision getSubdivision() { - return subdiv; - } - - /** - * Gets the {@link KdTree} which contains the vertices of the triangulation. - * - * @return a KdTree - */ - public KdTree getKDT() { - return kdt; - } - - /** - * Gets the sites (vertices) used to initialize the triangulation. - * - * @return a List of Vertex - */ - public List getInitialVertices() { - return initialVertices; - } - - /** - * Gets the {@link Segment}s which represent the constraints. - * - * @return a collection of Segments - */ - public Collection getConstraintSegments() { - return segments; - } - - /** - * Gets the convex hull of all the sites in the triangulation, - * including constraint vertices. - * Only valid after the constraints have been enforced. - * - * @return the convex hull of the sites - */ - public Geometry getConvexHull() { - return convexHull; - } - - // ================================================================== - - private void computeBoundingBox() { - Envelope vertexEnv = computeVertexEnvelope(initialVertices); - Envelope segEnv = computeVertexEnvelope(segVertices); - - Envelope allPointsEnv = new Envelope(vertexEnv); - allPointsEnv.expandToInclude(segEnv); - - double deltaX = allPointsEnv.getWidth() * 0.2; - double deltaY = allPointsEnv.getHeight() * 0.2; - - double delta = Math.max(deltaX, deltaY); - - computeAreaEnv = new Envelope(allPointsEnv); - computeAreaEnv.expandBy(delta); - } - - private void computeConvexHull() { - GeometryFactory fact = new GeometryFactory(); - Coordinate[] coords = getPointArray(); - ConvexHull hull = new ConvexHull(coords, fact); - convexHull = hull.getConvexHull(); - } - - // /** - // * Adds the segments in the Convex Hull of all sites in the input data as - // linear constraints. - // * This is required if TIN Refinement is performed. The hull segments are - // flagged with a - // unique - // * data object to allow distinguishing them. - // * - // * @param convexHullSegmentData the data object to attach to each convex - // hull segment - // */ - // private void addConvexHullToConstraints(Object convexHullSegmentData) { - // Coordinate[] coords = convexHull.getCoordinates(); - // for (int i = 1; i < coords.length; i++) { - // Segment s = new Segment(coords[i - 1], coords[i], convexHullSegmentData); - // addConstraintIfUnique(s); - // } - // } - - // private void addConstraintIfUnique(Segment r) { - // boolean exists = false; - // Iterator it = segments.iterator(); - // Segment s = null; - // while (it.hasNext()) { - // s = (Segment) it.next(); - // if (r.equalsTopo(s)) { - // exists = true; - // } - // } - // if (!exists) { - // segments.add((Object) r); - // } - // } - - private Coordinate[] getPointArray() { - Coordinate[] pts = new Coordinate[initialVertices.size() - + segVertices.size()]; - int index = 0; - for (Iterator i = initialVertices.iterator(); i.hasNext();) { - Vertex v = (Vertex) i.next(); - pts[index++] = v.getCoordinate(); - } - for (Iterator i2 = segVertices.iterator(); i2.hasNext();) { - Vertex v = (Vertex) i2.next(); - pts[index++] = v.getCoordinate(); - } - return pts; - } - - private ConstraintVertex createVertex(Coordinate p) { - ConstraintVertex v = null; - if (vertexFactory != null) - v = vertexFactory.createVertex(p, null); - else - v = new ConstraintVertex(p); - return v; - } - - /** - * Creates a vertex on a constraint segment - * - * @param p the location of the vertex to create - * @param seg the constraint segment it lies on - * @return the new constraint vertex - */ - private ConstraintVertex createVertex(Coordinate p, Segment seg) { - ConstraintVertex v = null; - if (vertexFactory != null) - v = vertexFactory.createVertex(p, seg); - else - v = new ConstraintVertex(p); - v.setOnConstraint(true); - return v; - } - - /** - * Inserts all sites in a collection - * - * @param vertices a collection of ConstraintVertex - */ - private void insertSites(Collection vertices) { - Debug.println("Adding sites: " + vertices.size()); - for (Iterator i = vertices.iterator(); i.hasNext();) { - ConstraintVertex v = (ConstraintVertex) i.next(); - insertSite(v); - } - } - - private ConstraintVertex insertSite(ConstraintVertex v) { - KdNode kdnode = kdt.insert(v.getCoordinate(), v); - if (!kdnode.isRepeated()) { - incDel.insertSite(v); - } else { - ConstraintVertex snappedV = (ConstraintVertex) kdnode.getData(); - snappedV.merge(v); - return snappedV; - // testing - // if ( v.isOnConstraint() && ! currV.isOnConstraint()) { - // System.out.println(v); - // } - } - return v; - } - - /** - * Inserts a site into the triangulation, maintaining the conformal Delaunay property. - * This can be used to further refine the triangulation if required - * (e.g. to approximate the medial axis of the constraints, - * or to improve the grading of the triangulation). - * - * @param p the location of the site to insert - */ - public void insertSite(Coordinate p) { - insertSite(createVertex(p)); - } - - // ================================================================== - - /** - * Computes the Delaunay triangulation of the initial sites. - */ - public void formInitialDelaunay() { - computeBoundingBox(); - subdiv = new QuadEdgeSubdivision(computeAreaEnv, tolerance); - subdiv.setLocator(new LastFoundQuadEdgeLocator(subdiv)); - incDel = new IncrementalDelaunayTriangulator(subdiv); - insertSites(initialVertices); - } - - // ================================================================== - - private final static int MAX_SPLIT_ITER = 99; - - /** - * Enforces the supplied constraints into the triangulation. - * - * @throws ConstraintEnforcementException - * if the constraints cannot be enforced - */ - public void enforceConstraints() { - addConstraintVertices(); - // if (true) return; - - int count = 0; - int splits = 0; - do { - splits = enforceGabriel(segments); - - count++; - Debug.println("Iter: " + count + " Splits: " + splits - + " Current # segments = " + segments.size()); - } while (splits > 0 && count < MAX_SPLIT_ITER); - if (count == MAX_SPLIT_ITER) { - Debug.println("ABORTED! Too many iterations while enforcing constraints"); - if (!Debug.isDebugging()) - throw new ConstraintEnforcementException( - "Too many splitting iterations while enforcing constraints. Last split point was at: ", - splitPt); - } - } - - private void addConstraintVertices() { - computeConvexHull(); - // insert constraint vertices as sites - insertSites(segVertices); - } - - /* - * private List findMissingConstraints() { List missingSegs = new ArrayList(); - * for (int i = 0; i < segments.size(); i++) { Segment s = (Segment) - * segments.get(i); QuadEdge q = subdiv.locate(s.getStart(), s.getEnd()); if - * (q == null) missingSegs.add(s); } return missingSegs; } - */ - - private int enforceGabriel(Collection segsToInsert) { - List newSegments = new ArrayList(); - int splits = 0; - List segsToRemove = new ArrayList(); - - /** - * On each iteration must always scan all constraint (sub)segments, since - * some constraints may be rebroken by Delaunay triangle flipping caused by - * insertion of another constraint. However, this process must converge - * eventually, with no splits remaining to find. - */ - for (Iterator i = segsToInsert.iterator(); i.hasNext();) { - Segment seg = (Segment) i.next(); - // System.out.println(seg); - - Coordinate encroachPt = findNonGabrielPoint(seg); - // no encroachment found - segment must already be in subdivision - if (encroachPt == null) - continue; - - // compute split point - splitPt = splitFinder.findSplitPoint(seg, encroachPt); - ConstraintVertex splitVertex = createVertex(splitPt, seg); - - // DebugFeature.addLineSegment(DEBUG_SEG_SPLIT, encroachPt, splitPt, ""); - // Debug.println(WKTWriter.toLineString(encroachPt, splitPt)); - - /** - * Check whether the inserted point still equals the split pt. This will - * not be the case if the split pt was too close to an existing site. If - * the point was snapped, the triangulation will not respect the inserted - * constraint - this is a failure. This can be caused by: - *
                          - *
                        • An initial site that lies very close to a constraint segment The - * cure for this is to remove any initial sites which are close to - * constraint segments in a preprocessing phase. - *
                        • A narrow constraint angle which causing repeated splitting until - * the split segments are too small. The cure for this is to either choose - * better split points or "guard" narrow angles by cracking the segments - * equidistant from the corner. - *
                        - */ - ConstraintVertex insertedVertex = insertSite(splitVertex); - if (!insertedVertex.getCoordinate().equals2D(splitPt)) { - Debug.println("Split pt snapped to: " + insertedVertex); - // throw new ConstraintEnforcementException("Split point snapped to - // existing point - // (tolerance too large or constraint interior narrow angle?)", - // splitPt); - } - - // split segment and record the new halves - Segment s1 = new Segment(seg.getStartX(), seg.getStartY(), seg - .getStartZ(), splitVertex.getX(), splitVertex.getY(), splitVertex - .getZ(), seg.getData()); - Segment s2 = new Segment(splitVertex.getX(), splitVertex.getY(), - splitVertex.getZ(), seg.getEndX(), seg.getEndY(), seg.getEndZ(), seg - .getData()); - newSegments.add(s1); - newSegments.add(s2); - segsToRemove.add(seg); - - splits = splits + 1; - } - segsToInsert.removeAll(segsToRemove); - segsToInsert.addAll(newSegments); - - return splits; - } - -// public static final String DEBUG_SEG_SPLIT = "C:\\proj\\CWB\\test\\segSplit.jml"; - - /** - * Given a set of points stored in the kd-tree and a line segment defined by - * two points in this set, finds a {@link Coordinate} in the circumcircle of - * the line segment, if one exists. This is called the Gabriel point - if none - * exists then the segment is said to have the Gabriel condition. Uses the - * heuristic of finding the non-Gabriel point closest to the midpoint of the - * segment. - * - * @param p - * start of the line segment - * @param q - * end of the line segment - * @return a point which is non-Gabriel - * or null if no point is non-Gabriel - */ - private Coordinate findNonGabrielPoint(Segment seg) { - Coordinate p = seg.getStart(); - Coordinate q = seg.getEnd(); - // Find the mid point on the line and compute the radius of enclosing circle - Coordinate midPt = new Coordinate((p.x + q.x) / 2.0, (p.y + q.y) / 2.0); - double segRadius = p.distance(midPt); - - // compute envelope of circumcircle - Envelope env = new Envelope(midPt); - env.expandBy(segRadius); - // Find all points in envelope - List result = kdt.query(env); - - // For each point found, test if it falls strictly in the circle - // find closest point - Coordinate closestNonGabriel = null; - double minDist = Double.MAX_VALUE; - for (Iterator i = result.iterator(); i.hasNext();) { - KdNode nextNode = (KdNode) i.next(); - Coordinate testPt = nextNode.getCoordinate(); - // ignore segment endpoints - if (testPt.equals2D(p) || testPt.equals2D(q)) - continue; - - double testRadius = midPt.distance(testPt); - if (testRadius < segRadius) { - // double testDist = seg.distance(testPt); - double testDist = testRadius; - if (closestNonGabriel == null || testDist < minDist) { - closestNonGabriel = testPt; - minDist = testDist; - } - } - } - return closestNonGabriel; - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintEnforcementException.java b/src/main/java/com/vividsolutions/jts/triangulate/ConstraintEnforcementException.java deleted file mode 100644 index 77f2750582..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintEnforcementException.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * Indicates a failure during constraint enforcement. - * - * @author Martin Davis - * @version 1.0 - */ -public class ConstraintEnforcementException extends RuntimeException { - - private static final long serialVersionUID = 386496846550080140L; - - private static String msgWithCoord(String msg, Coordinate pt) { - if (pt != null) - return msg + " [ " + WKTWriter.toPoint(pt) + " ]"; - return msg; - } - - private Coordinate pt = null; - - /** - * Creates a new instance with a given message. - * - * @param msg a string - */ - public ConstraintEnforcementException(String msg) { - super(msg); - } - - /** - * Creates a new instance with a given message and approximate location. - * - * @param msg a string - * @param pt the location of the error - */ - public ConstraintEnforcementException(String msg, Coordinate pt) { - super(msgWithCoord(msg, pt)); - this.pt = new Coordinate(pt); - } - - /** - * Gets the approximate location of this error. - * - * @return a location - */ - public Coordinate getCoordinate() { - return pt; - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintSplitPointFinder.java b/src/main/java/com/vividsolutions/jts/triangulate/ConstraintSplitPointFinder.java deleted file mode 100644 index 2a6b944fdd..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintSplitPointFinder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * An interface for strategies for determining the location of split points on constraint segments. - * The location of split points has a large effect on the performance and robustness of enforcing a - * constrained Delaunay triangulation. Poorly chosen split points can cause repeated splitting, - * especially at narrow constraint angles, since the split point will end up encroaching on the - * segment containing the original encroaching point. With detailed knowledge of the geometry of the - * constraints, it is sometimes possible to choose better locations for splitting. - * - * @author mbdavis - */ -public interface ConstraintSplitPointFinder { - /** - * Finds a point at which to split an encroached segment to allow the original segment to appear - * as edges in a constrained Delaunay triangulation. - * - * @param seg the encroached segment - * @param encroachPt the encroaching point - * @return the point at which to split the encroached segment - */ - Coordinate findSplitPoint(Segment seg, Coordinate encroachPt); -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertex.java b/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertex.java deleted file mode 100644 index 66ee493921..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertex.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.triangulate; - - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.triangulate.quadedge.Vertex; - -/** - * A vertex in a Constrained Delaunay Triangulation. - * The vertex may or may not lie on a constraint. - * If it does it may carry extra information about the original constraint. - * - * @author Martin Davis - */ -public class ConstraintVertex extends Vertex { - private boolean isOnConstraint; - private Object constraint = null; - - /** - * Creates a new constraint vertex - * - * @param p the location of the vertex - */ - public ConstraintVertex(Coordinate p) { - super(p); - } - - /** - * Sets whether this vertex lies on a constraint. - * - * @param isOnConstraint true if this vertex lies on a constraint - */ - public void setOnConstraint(boolean isOnConstraint) { - this.isOnConstraint = isOnConstraint; - } - - /** - * Tests whether this vertex lies on a constraint. - * - * @return true if the vertex lies on a constraint - */ - public boolean isOnConstraint() { - return isOnConstraint; - } - - /** - * Sets the external constraint information - * - * @param constraint an object which carries information about the constraint this vertex lies on - */ - public void setConstraint(Object constraint) { - isOnConstraint = true; - this.constraint = constraint; - } - - /** - * Gets the external constraint object - * - * @return the external constraint object - */ - public Object getConstraint() { - return constraint; - } - - /** - * Merges the constraint data in the vertex other into this vertex. - * This method is called when an inserted vertex is - * very close to an existing vertex in the triangulation. - * - * @param other the constraint vertex to merge - */ - protected void merge(ConstraintVertex other) { - if (other.isOnConstraint) { - isOnConstraint = true; - constraint = other.constraint; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertexFactory.java b/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertexFactory.java deleted file mode 100644 index ee26be2242..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/ConstraintVertexFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.triangulate.quadedge.Vertex; - -/** - * An interface for factories which create a {@link ConstraintVertex} - * - * @author Martin Davis - */ -public interface ConstraintVertexFactory { - ConstraintVertex createVertex(Coordinate p, Segment constraintSeg); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/DelaunayTriangulationBuilder.java b/src/main/java/com/vividsolutions/jts/triangulate/DelaunayTriangulationBuilder.java deleted file mode 100644 index 3b6ebfab01..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/DelaunayTriangulationBuilder.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.triangulate; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.triangulate.quadedge.*; - -/** - * A utility class which creates Delaunay Trianglulations - * from collections of points and extract the resulting - * triangulation edges or triangles as geometries. - * - * @author Martin Davis - * - */ -public class DelaunayTriangulationBuilder -{ - /** - * Extracts the unique {@link Coordinate}s from the given {@link Geometry}. - * @param geom the geometry to extract from - * @return a List of the unique Coordinates - */ - public static CoordinateList extractUniqueCoordinates(Geometry geom) - { - if (geom == null) - return new CoordinateList(); - - Coordinate[] coords = geom.getCoordinates(); - return unique(coords); - } - - public static CoordinateList unique(Coordinate[] coords) - { - Coordinate[] coordsCopy = CoordinateArrays.copyDeep(coords); - Arrays.sort(coordsCopy); - CoordinateList coordList = new CoordinateList(coordsCopy, false); - return coordList; - } - - /** - * Converts all {@link Coordinate}s in a collection to {@link Vertex}es. - * @param coords the coordinates to convert - * @return a List of Vertex objects - */ - public static List toVertices(Collection coords) - { - List verts = new ArrayList(); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate coord = (Coordinate) i.next(); - verts.add(new Vertex(coord)); - } - return verts; - } - - /** - * Computes the {@link Envelope} of a collection of {@link Coordinate}s. - * - * @param coords a List of Coordinates - * @return the envelope of the set of coordinates - */ - public static Envelope envelope(Collection coords) - { - Envelope env = new Envelope(); - for (Iterator i = coords.iterator(); i.hasNext(); ) { - Coordinate coord = (Coordinate) i.next(); - env.expandToInclude(coord); - } - return env; - } - - private Collection siteCoords; - private double tolerance = 0.0; - private QuadEdgeSubdivision subdiv = null; - - /** - * Creates a new triangulation builder. - * - */ - public DelaunayTriangulationBuilder() - { - } - - /** - * Sets the sites (vertices) which will be triangulated. - * All vertices of the given geometry will be used as sites. - * - * @param geom the geometry from which the sites will be extracted. - */ - public void setSites(Geometry geom) - { - // remove any duplicate points (they will cause the triangulation to fail) - siteCoords = extractUniqueCoordinates(geom); - } - - /** - * Sets the sites (vertices) which will be triangulated - * from a collection of {@link Coordinate}s. - * - * @param coords a collection of Coordinates. - */ - public void setSites(Collection coords) - { - // remove any duplicate points (they will cause the triangulation to fail) - siteCoords = unique(CoordinateArrays.toCoordinateArray(coords)); - } - - /** - * Sets the snapping tolerance which will be used - * to improved the robustness of the triangulation computation. - * A tolerance of 0.0 specifies that no snapping will take place. - * - * @param tolerance the tolerance distance to use - */ - public void setTolerance(double tolerance) - { - this.tolerance = tolerance; - } - - private void create() - { - if (subdiv != null) return; - - Envelope siteEnv = envelope(siteCoords); - List vertices = toVertices(siteCoords); - subdiv = new QuadEdgeSubdivision(siteEnv, tolerance); - IncrementalDelaunayTriangulator triangulator = new IncrementalDelaunayTriangulator(subdiv); - triangulator.insertSites(vertices); - } - - /** - * Gets the {@link QuadEdgeSubdivision} which models the computed triangulation. - * - * @return the subdivision containing the triangulation - */ - public QuadEdgeSubdivision getSubdivision() - { - create(); - return subdiv; - } - - /** - * Gets the edges of the computed triangulation as a {@link MultiLineString}. - * - * @param geomFact the geometry factory to use to create the output - * @return the edges of the triangulation - */ - public Geometry getEdges(GeometryFactory geomFact) - { - create(); - return subdiv.getEdges(geomFact); - } - - /** - * Gets the faces of the computed triangulation as a {@link GeometryCollection} - * of {@link Polygon}. - * - * @param geomFact the geometry factory to use to create the output - * @return the faces of the triangulation - */ - public Geometry getTriangles(GeometryFactory geomFact) - { - create(); - return subdiv.getTriangles(geomFact); - } -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java b/src/main/java/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java deleted file mode 100644 index f6c1d8ed74..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - -import java.util.Collection; -import java.util.Iterator; - -import com.vividsolutions.jts.triangulate.quadedge.LocateFailureException; -import com.vividsolutions.jts.triangulate.quadedge.QuadEdge; -import com.vividsolutions.jts.triangulate.quadedge.QuadEdgeSubdivision; -import com.vividsolutions.jts.triangulate.quadedge.Vertex; - -/** - * Computes a Delauanay Triangulation of a set of {@link Vertex}es, using an - * incrementatal insertion algorithm. - * - * @author Martin Davis - * @version 1.0 - */ -public class IncrementalDelaunayTriangulator -{ - private QuadEdgeSubdivision subdiv; - private boolean isUsingTolerance = false; - - /** - * Creates a new triangulator using the given {@link QuadEdgeSubdivision}. - * The triangulator uses the tolerance of the supplied subdivision. - * - * @param subdiv - * a subdivision in which to build the TIN - */ - public IncrementalDelaunayTriangulator(QuadEdgeSubdivision subdiv) { - this.subdiv = subdiv; - isUsingTolerance = subdiv.getTolerance() > 0.0; - - } - - /** - * Inserts all sites in a collection. The inserted vertices MUST be - * unique up to the provided tolerance value. (i.e. no two vertices should be - * closer than the provided tolerance value). They do not have to be rounded - * to the tolerance grid, however. - * - * @param vertices a Collection of Vertex - * - * @throws LocateFailureException if the location algorithm fails to converge in a reasonable number of iterations - */ - public void insertSites(Collection vertices) { - for (Iterator i = vertices.iterator(); i.hasNext();) { - Vertex v = (Vertex) i.next(); - insertSite(v); - } - } - - /** - * Inserts a new point into a subdivision representing a Delaunay - * triangulation, and fixes the affected edges so that the result is still a - * Delaunay triangulation. - *

                        - * - * @return a quadedge containing the inserted vertex - */ - public QuadEdge insertSite(Vertex v) { - - /** - * This code is based on Guibas and Stolfi (1985), with minor modifications - * and a bug fix from Dani Lischinski (Graphic Gems 1993). (The modification - * I believe is the test for the inserted site falling exactly on an - * existing edge. Without this test zero-width triangles have been observed - * to be created) - */ - QuadEdge e = subdiv.locate(v); - - if (subdiv.isVertexOfEdge(e, v)) { - // point is already in subdivision. - return e; - } - else if (subdiv.isOnEdge(e, v.getCoordinate())) { - // the point lies exactly on an edge, so delete the edge - // (it will be replaced by a pair of edges which have the point as a vertex) - e = e.oPrev(); - subdiv.delete(e.oNext()); - } - - /** - * Connect the new point to the vertices of the containing triangle - * (or quadrilateral, if the new point fell on an existing edge.) - */ - QuadEdge base = subdiv.makeEdge(e.orig(), v); - QuadEdge.splice(base, e); - QuadEdge startEdge = base; - do { - base = subdiv.connect(e, base.sym()); - e = base.oPrev(); - } while (e.lNext() != startEdge); - - // Examine suspect edges to ensure that the Delaunay condition - // is satisfied. - do { - QuadEdge t = e.oPrev(); - if (t.dest().rightOf(e) && v.isInCircle(e.orig(), t.dest(), e.dest())) { - QuadEdge.swap(e); - e = e.oPrev(); - } else if (e.oNext() == startEdge) { - return base; // no more suspect edges. - } else { - e = e.oNext().lPrev(); - } - } while (true); - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/MidpointSplitPointFinder.java b/src/main/java/com/vividsolutions/jts/triangulate/MidpointSplitPointFinder.java deleted file mode 100644 index 83f1218bae..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/MidpointSplitPointFinder.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - - -import com.vividsolutions.jts.geom.Coordinate; - -/** - * A simple split point finder which returns the midpoint of the split segment. This is a default - * strategy only. Usually a more sophisticated strategy is required to prevent repeated splitting. - * Other points which could be used are: - *

                          - *
                        • The projection of the encroaching point on the segment - *
                        • A point on the segment which will produce two segments which will not be further encroached - *
                        • The point on the segment which is the same distance from an endpoint as the encroaching - * point - *
                        - * - * @author Martin Davis - */ -public class MidpointSplitPointFinder implements ConstraintSplitPointFinder { - /** - * Gets the midpoint of the split segment - */ - public Coordinate findSplitPoint(Segment seg, Coordinate encroachPt) { - Coordinate p0 = seg.getStart(); - Coordinate p1 = seg.getEnd(); - return new Coordinate((p0.x + p1.x) / 2, (p0.y + p1.y) / 2); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/NonEncroachingSplitPointFinder.java b/src/main/java/com/vividsolutions/jts/triangulate/NonEncroachingSplitPointFinder.java deleted file mode 100644 index 9efc7f7003..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/NonEncroachingSplitPointFinder.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.LineSegment; - -/** - * A strategy for finding constraint split points which attempts to maximise the length of the split - * segments while preventing further encroachment. (This is not always possible for narrow angles). - * - * @author Martin Davis - */ -public class NonEncroachingSplitPointFinder implements ConstraintSplitPointFinder { - - public NonEncroachingSplitPointFinder() {} - - /** - * A basic strategy for finding split points when nothing extra is known about the geometry of - * the situation. - * - * @param seg the encroached segment - * @param encroachPt the encroaching point - * @return the point at which to split the encroached segment - */ - public Coordinate findSplitPoint(Segment seg, Coordinate encroachPt) { - LineSegment lineSeg = seg.getLineSegment(); - double segLen = lineSeg.getLength(); - double midPtLen = segLen / 2; - SplitSegment splitSeg = new SplitSegment(lineSeg); - - Coordinate projPt = projectedSplitPoint(seg, encroachPt); - /** - * Compute the largest diameter (length) that will produce a split segment which is not - * still encroached upon by the encroaching point (The length is reduced slightly by a - * safety factor) - */ - double nonEncroachDiam = projPt.distance(encroachPt) * 2 * 0.8; // .99; - double maxSplitLen = nonEncroachDiam; - if (maxSplitLen > midPtLen) { - maxSplitLen = midPtLen; - } - splitSeg.setMinimumLength(maxSplitLen); - - splitSeg.splitAt(projPt); - - return splitSeg.getSplitPoint(); - } - - /** - * Computes a split point which is the projection of the encroaching point on the segment - * - * @param seg - * @param encroachPt - * @return a split point on the segment - */ - public static Coordinate projectedSplitPoint(Segment seg, Coordinate encroachPt) { - LineSegment lineSeg = seg.getLineSegment(); - Coordinate projPt = lineSeg.project(encroachPt); - return projPt; - } -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/Segment.java b/src/main/java/com/vividsolutions/jts/triangulate/Segment.java deleted file mode 100644 index 9374d66beb..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/Segment.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.LineSegment; - -/** - * Models a constraint segment in a triangulation. - * A constraint segment is an oriented straight line segment between a start point - * and an end point. - * - * @author David Skea - * @author Martin Davis - */ -public class Segment -{ - private LineSegment ls; - private Object data = null; - - /** - * Creates a new instance for the given ordinates. - */ - public Segment(double x1, double y1, double z1, double x2, double y2, double z2) { - this(new Coordinate(x1, y1, z1), new Coordinate(x2, y2, z2)); - } - - /** - * Creates a new instance for the given ordinates, with associated external data. - */ - public Segment(double x1, double y1, double z1, double x2, double y2, double z2, Object data) { - this(new Coordinate(x1, y1, z1), new Coordinate(x2, y2, z2), data); - } - - /** - * Creates a new instance for the given points, with associated external data. - * - * @param p0 the start point - * @param p1 the end point - * @param data an external data object - */ - public Segment(Coordinate p0, Coordinate p1, Object data) { - ls = new LineSegment(p0, p1); - this.data = data; - } - - /** - * Creates a new instance for the given points. - * - * @param p0 the start point - * @param p1 the end point - */ - public Segment(Coordinate p0, Coordinate p1) { - ls = new LineSegment(p0, p1); - } - - /** - * Gets the start coordinate of the segment - * - * @return a Coordinate - */ - public Coordinate getStart() { - return ls.getCoordinate(0); - } - - /** - * Gets the end coordinate of the segment - * - * @return a Coordinate - */ - public Coordinate getEnd() { - return ls.getCoordinate(1); - } - - /** - * Gets the start X ordinate of the segment - * - * @return the X ordinate value - */ - public double getStartX() { - Coordinate p = ls.getCoordinate(0); - return p.x; - } - - /** - * Gets the start Y ordinate of the segment - * - * @return the Y ordinate value - */ - public double getStartY() { - Coordinate p = ls.getCoordinate(0); - return p.y; - } - - /** - * Gets the start Z ordinate of the segment - * - * @return the Z ordinate value - */ - public double getStartZ() { - Coordinate p = ls.getCoordinate(0); - return p.z; - } - - /** - * Gets the end X ordinate of the segment - * - * @return the X ordinate value - */ - public double getEndX() { - Coordinate p = ls.getCoordinate(1); - return p.x; - } - - /** - * Gets the end Y ordinate of the segment - * - * @return the Y ordinate value - */ - public double getEndY() { - Coordinate p = ls.getCoordinate(1); - return p.y; - } - - /** - * Gets the end Z ordinate of the segment - * - * @return the Z ordinate value - */ - public double getEndZ() { - Coordinate p = ls.getCoordinate(1); - return p.z; - } - - /** - * Gets a LineSegment modelling this segment. - * - * @return a LineSegment - */ - public LineSegment getLineSegment() { - return ls; - } - - /** - * Gets the external data associated with this segment - * - * @return a data object - */ - public Object getData() { - return data; - } - - /** - * Sets the external data to be associated with this segment - * - * @param data a data object - */ - public void setData(Object data) { - this.data = data; - } - - /** - * Determines whether two segments are topologically equal. - * I.e. equal up to orientation. - * - * @param s a segment - * @return true if the segments are topologically equal - */ - public boolean equalsTopo(Segment s) { - return ls.equalsTopo(s.getLineSegment()); - } - - /** - * Computes the intersection point between this segment and another one. - * - * @param s a segment - * @return the intersection point, or null if there is none - */ - public Coordinate intersection(Segment s) { - return ls.intersection(s.getLineSegment()); - } - - /** - * Computes a string representation of this segment. - * - * @return a string - */ - public String toString() { - return ls.toString(); - } -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/SplitSegment.java b/src/main/java/com/vividsolutions/jts/triangulate/SplitSegment.java deleted file mode 100644 index fd5a8b1c84..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/SplitSegment.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.LineSegment; - -/** - * Models a constraint segment which can be split in two in various ways, - * according to certain geometric constraints. - * - * @author Martin Davis - */ -public class SplitSegment { - /** - * Computes the {@link Coordinate} that lies a given fraction along the line defined by the - * reverse of the given segment. A fraction of 0.0 returns the end point of the - * segment; a fraction of 1.0 returns the start point of the segment. - * - * @param seg the LineSegment - * @param segmentLengthFraction the fraction of the segment length along the line - * @return the point at that distance - */ - private static Coordinate pointAlongReverse(LineSegment seg, double segmentLengthFraction) { - Coordinate coord = new Coordinate(); - coord.x = seg.p1.x - segmentLengthFraction * (seg.p1.x - seg.p0.x); - coord.y = seg.p1.y - segmentLengthFraction * (seg.p1.y - seg.p0.y); - return coord; - } - - private LineSegment seg; - private double segLen; - private Coordinate splitPt; - private double minimumLen = 0.0; - - public SplitSegment(LineSegment seg) { - this.seg = seg; - segLen = seg.getLength(); - } - - public void setMinimumLength(double minLen) { - minimumLen = minLen; - } - - public Coordinate getSplitPoint() { - return splitPt; - } - - public void splitAt(double length, Coordinate endPt) { - double actualLen = getConstrainedLength(length); - double frac = actualLen / segLen; - if (endPt.equals2D(seg.p0)) - splitPt = seg.pointAlong(frac); - else - splitPt = pointAlongReverse(seg, frac); - } - - public void splitAt(Coordinate pt) { - // check that given pt doesn't violate min length - double minFrac = minimumLen / segLen; - if (pt.distance(seg.p0) < minimumLen) { - splitPt = seg.pointAlong(minFrac); - return; - } - if (pt.distance(seg.p1) < minimumLen) { - splitPt = pointAlongReverse(seg, minFrac); - return; - } - // passes minimum distance check - use provided point as split pt - splitPt = pt; - } - - private double getConstrainedLength(double len) { - if (len < minimumLen) - return minimumLen; - return len; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/VertexTaggedGeometryDataMapper.java b/src/main/java/com/vividsolutions/jts/triangulate/VertexTaggedGeometryDataMapper.java deleted file mode 100644 index 3535981d1a..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/VertexTaggedGeometryDataMapper.java +++ /dev/null @@ -1,108 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.triangulate; - -import java.util.*; -import com.vividsolutions.jts.geom.*; - -/** - * Creates a map between the vertex {@link Coordinate}s of a - * set of {@link Geometry}s, - * and the parent geometry, and transfers the source geometry - * data objects to geometry components tagged with the coordinates. - *

                        - * This class can be used in conjunction with {@link VoronoiDiagramBuilder} - * to transfer data objects from the input site geometries - * to the constructed Voronoi polygons. - * - * @author Martin Davis - * @see VoronoiDiagramBuilder - * - */ -public class VertexTaggedGeometryDataMapper -{ - private Map coordDataMap = new TreeMap(); - - public VertexTaggedGeometryDataMapper() - { - - } - - public void loadSourceGeometries(Collection geoms) - { - for (Iterator i = geoms.iterator(); i.hasNext(); ) { - Geometry geom = (Geometry) i.next(); - loadVertices(geom.getCoordinates(), geom.getUserData()); - } - } - - public void loadSourceGeometries(Geometry geomColl) - { - for (int i = 0; i < geomColl.getNumGeometries(); i++) { - Geometry geom = geomColl.getGeometryN(i); - loadVertices(geom.getCoordinates(), geom.getUserData()); - } - } - - private void loadVertices(Coordinate[] pts, Object data) - { - for (int i = 0; i < pts.length; i++) { - coordDataMap.put(pts[i], data); - } - } - - public List getCoordinates() - { - return new ArrayList(coordDataMap.keySet()); - } - - /** - * Input is assumed to be a multiGeometry - * in which every component has its userData - * set to be a Coordinate which is the key to the output data. - * The Coordinate is used to determine - * the output data object to be written back into the component. - * - * @param targetGeom - */ - public void transferData(Geometry targetGeom) - { - for (int i = 0; i < targetGeom.getNumGeometries(); i++) { - Geometry geom = targetGeom.getGeometryN(i); - Coordinate vertexKey = (Coordinate) geom.getUserData(); - if (vertexKey == null) continue; - geom.setUserData(coordDataMap.get(vertexKey)); - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/VoronoiDiagramBuilder.java b/src/main/java/com/vividsolutions/jts/triangulate/VoronoiDiagramBuilder.java deleted file mode 100644 index 22f1fb2c70..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/VoronoiDiagramBuilder.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.triangulate; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.triangulate.quadedge.*; - -/** - * A utility class which creates Voronoi Diagrams - * from collections of points. - * The diagram is returned as a {@link GeometryCollection} of {@link Polygon}s - * representing the faces of the Voronoi diagram. - * The faces are clipped to the larger of: - *

                          - *
                        • an envelope supplied by {@link #setClipEnvelope(Envelope)} - *
                        • an envelope determined by the input sites - *
                        - * The userData attribute of each face Polygon is set to - * the Coordinate of the corresponding input site. - * This allows using a Map to link faces to data associated with sites. - * - * @author Martin Davis - * - */ -public class VoronoiDiagramBuilder -{ - private Collection siteCoords; - private double tolerance = 0.0; - private QuadEdgeSubdivision subdiv = null; - private Envelope clipEnv = null; - private Envelope diagramEnv = null; - - /** - * Creates a new Voronoi diagram builder. - * - */ - public VoronoiDiagramBuilder() - { - } - - /** - * Sets the sites (point or vertices) which will be diagrammed. - * All vertices of the given geometry will be used as sites. - * - * @param geom the geometry from which the sites will be extracted. - */ - public void setSites(Geometry geom) - { - // remove any duplicate points (they will cause the triangulation to fail) - siteCoords = DelaunayTriangulationBuilder.extractUniqueCoordinates(geom); - } - - /** - * Sets the sites (point or vertices) which will be diagrammed - * from a collection of {@link Coordinate}s. - * - * @param coords a collection of Coordinates. - */ - public void setSites(Collection coords) - { - // remove any duplicate points (they will cause the triangulation to fail) - siteCoords = DelaunayTriangulationBuilder.unique(CoordinateArrays.toCoordinateArray(coords)); - } - - /** - * Sets the envelope to clip the diagram to. - * The diagram will be clipped to the larger - * of this envelope or an envelope surrounding the sites. - * - * @param clipEnv the clip envelope. - */ - public void setClipEnvelope(Envelope clipEnv) - { - this.clipEnv = clipEnv; - } - /** - * Sets the snapping tolerance which will be used - * to improved the robustness of the triangulation computation. - * A tolerance of 0.0 specifies that no snapping will take place. - * - * @param tolerance the tolerance distance to use - */ - public void setTolerance(double tolerance) - { - this.tolerance = tolerance; - } - - private void create() - { - if (subdiv != null) return; - - Envelope siteEnv = DelaunayTriangulationBuilder.envelope(siteCoords); - diagramEnv = siteEnv; - // add a buffer around the final envelope - double expandBy = Math.max(diagramEnv.getWidth(), diagramEnv.getHeight()); - diagramEnv.expandBy(expandBy); - if (clipEnv != null) - diagramEnv.expandToInclude(clipEnv); - - List vertices = DelaunayTriangulationBuilder.toVertices(siteCoords); - subdiv = new QuadEdgeSubdivision(siteEnv, tolerance); - IncrementalDelaunayTriangulator triangulator = new IncrementalDelaunayTriangulator(subdiv); - triangulator.insertSites(vertices); - } - - /** - * Gets the {@link QuadEdgeSubdivision} which models the computed diagram. - * - * @return the subdivision containing the triangulation - */ - public QuadEdgeSubdivision getSubdivision() - { - create(); - return subdiv; - } - - /** - * Gets the faces of the computed diagram as a {@link GeometryCollection} - * of {@link Polygon}s, clipped as specified. - *

                        - * The userData attribute of each face Polygon is set to - * the Coordinate of the corresponding input site. - * This allows using a Map to link faces to data associated with sites. - * - * @param geomFact the geometry factory to use to create the output - * @return a GeometryCollection containg the face Polgyons of the diagram - */ - public Geometry getDiagram(GeometryFactory geomFact) - { - create(); - Geometry polys = subdiv.getVoronoiDiagram(geomFact); - - // clip polys to diagramEnv - return clipGeometryCollection(polys, diagramEnv); - } - - private static Geometry clipGeometryCollection(Geometry geom, Envelope clipEnv) - { - Geometry clipPoly = geom.getFactory().toGeometry(clipEnv); - List clipped = new ArrayList(); - for (int i = 0; i < geom.getNumGeometries(); i++) { - Geometry g = geom.getGeometryN(i); - Geometry result = null; - // don't clip unless necessary - if (clipEnv.contains(g.getEnvelopeInternal())) - result = g; - else if (clipEnv.intersects(g.getEnvelopeInternal())) { - result = clipPoly.intersection(g); - // keep vertex key info - result.setUserData(g.getUserData()); - } - - if (result != null && ! result.isEmpty()) { - clipped.add(result); - } - } - return geom.getFactory().createGeometryCollection(GeometryFactory.toGeometryArray(clipped)); - } -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/EdgeConnectedTriangleTraversal.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/EdgeConnectedTriangleTraversal.java deleted file mode 100644 index 69a826e26e..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/EdgeConnectedTriangleTraversal.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import java.util.Collection; -import java.util.LinkedList; - -/** - * A framework to visit sets of edge-connected {@link QuadEdgeTriangle}s in breadth-first order - * - * @author Martin Davis - * @version 1.0 - */ -public class EdgeConnectedTriangleTraversal { - private LinkedList triQueue = new LinkedList(); - - public EdgeConnectedTriangleTraversal() {} - - public void init(QuadEdgeTriangle tri) { - triQueue.addLast(tri); - } - - /** - * Called to initialize the traversal queue with a given set of {@link QuadEdgeTriangle}s - * - * @param tris a collection of QuadEdgeTriangle - */ - public void init(Collection tris) { - triQueue.addAll(tris); - } - - /** - * Subclasses can call this method to add a triangle to the end of the queue. This is useful for - * initializing the queue to a chosen set of triangles. - * - * @param tri a triangle - */ - /* - * protected void addLast(QuadEdgeTriangle tri) { triQueue.addLast(tri); } - */ - - /** - * Subclasses call this method to perform the visiting process. - */ - public void visitAll(TraversalVisitor visitor) { - while (!triQueue.isEmpty()) { - QuadEdgeTriangle tri = (QuadEdgeTriangle) triQueue.removeFirst(); - process(tri, visitor); - } - } - - private void process(QuadEdgeTriangle currTri, TraversalVisitor visitor) { - currTri.getNeighbours(); - for (int i = 0; i < 3; i++) { - QuadEdgeTriangle neighTri = (QuadEdgeTriangle) currTri.getEdge(i).sym().getData(); - if (neighTri == null) - continue; - if (visitor.visit(currTri, i, neighTri)) - triQueue.addLast(neighTri); - } - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LastFoundQuadEdgeLocator.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LastFoundQuadEdgeLocator.java deleted file mode 100644 index 32cf81327e..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LastFoundQuadEdgeLocator.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import java.util.Collection; - -/** - * Locates {@link QuadEdge}s in a {@link QuadEdgeSubdivision}, - * optimizing the search by starting in the - * locality of the last edge found. - * - * @author Martin Davis - */ -public class LastFoundQuadEdgeLocator implements QuadEdgeLocator { - private QuadEdgeSubdivision subdiv; - private QuadEdge lastEdge = null; - - public LastFoundQuadEdgeLocator(QuadEdgeSubdivision subdiv) { - this.subdiv = subdiv; - init(); - } - - private void init() { - lastEdge = findEdge(); - } - - private QuadEdge findEdge() { - Collection edges = subdiv.getEdges(); - // assume there is an edge - otherwise will get an exception - return (QuadEdge) edges.iterator().next(); - } - - /** - * Locates an edge e, such that either v is on e, or e is an edge of a triangle containing v. - * The search starts from the last located edge amd proceeds on the general direction of v. - */ - public QuadEdge locate(Vertex v) { - if (! lastEdge.isLive()) { - init(); - } - - QuadEdge e = subdiv.locateFromEdge(v, lastEdge); - lastEdge = e; - return e; - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LocateFailureException.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LocateFailureException.java deleted file mode 100644 index f59314e904..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/LocateFailureException.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.triangulate.quadedge; - -import com.vividsolutions.jts.geom.*; - -public class LocateFailureException - extends RuntimeException -{ - private static String msgWithSpatial(String msg, LineSegment seg) { - if (seg != null) - return msg + " [ " + seg + " ]"; - return msg; - } - - private LineSegment seg = null; - - public LocateFailureException(String msg) { - super(msg); - } - - public LocateFailureException(String msg, LineSegment seg) { - super(msgWithSpatial(msg, seg)); - this.seg = new LineSegment(seg); - } - - public LocateFailureException(LineSegment seg) { - super( - "Locate failed to converge (at edge: " - + seg - + "). Possible causes include invalid Subdivision topology or very close sites"); - this.seg = new LineSegment(seg); - } - - public LineSegment getSegment() { - return seg; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdge.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdge.java deleted file mode 100644 index 928161b1bb..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdge.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * A class that represents the edge data structure which implements the quadedge algebra. - * The quadedge algebra was described in a well-known paper by Guibas and Stolfi, - * "Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams", - * ACM Transactions on Graphics, 4(2), 1985, 75-123. - *

                        - * Each edge object is part of a quartet of 4 edges, - * linked via their rot references. - * Any edge in the group may be accessed using a series of {@link #rot()} operations. - * Quadedges in a subdivision are linked together via their next references. - * The linkage between the quadedge quartets determines the topology - * of the subdivision. - *

                        - * The edge class does not contain separate information for vertice or faces; a vertex is implicitly - * defined as a ring of edges (created using the next field). - * - * @author David Skea - * @author Martin Davis - */ -public class QuadEdge -{ - /** - * Creates a new QuadEdge quartet from {@link Vertex} o to {@link Vertex} d. - * - * @param o - * the origin Vertex - * @param d - * the destination Vertex - * @return the new QuadEdge quartet - */ - public static QuadEdge makeEdge(Vertex o, Vertex d) { - QuadEdge q0 = new QuadEdge(); - QuadEdge q1 = new QuadEdge(); - QuadEdge q2 = new QuadEdge(); - QuadEdge q3 = new QuadEdge(); - - q0.rot = q1; - q1.rot = q2; - q2.rot = q3; - q3.rot = q0; - - q0.setNext(q0); - q1.setNext(q3); - q2.setNext(q2); - q3.setNext(q1); - - QuadEdge base = q0; - base.setOrig(o); - base.setDest(d); - return base; - } - - /** - * Creates a new QuadEdge connecting the destination of a to the origin of - * b, in such a way that all three have the same left face after the - * connection is complete. Additionally, the data pointers of the new edge - * are set. - * - * @return the connected edge. - */ - public static QuadEdge connect(QuadEdge a, QuadEdge b) { - QuadEdge e = makeEdge(a.dest(), b.orig()); - splice(e, a.lNext()); - splice(e.sym(), b); - return e; - } - - /** - * Splices two edges together or apart. - * Splice affects the two edge rings around the origins of a and b, and, independently, the two - * edge rings around the left faces of a and b. - * In each case, (i) if the two rings are distinct, - * Splice will combine them into one, or (ii) if the two are the same ring, Splice will break it - * into two separate pieces. Thus, Splice can be used both to attach the two edges together, and - * to break them apart. - * - * @param a an edge to splice - * @param b an edge to splice - * - */ - public static void splice(QuadEdge a, QuadEdge b) { - QuadEdge alpha = a.oNext().rot(); - QuadEdge beta = b.oNext().rot(); - - QuadEdge t1 = b.oNext(); - QuadEdge t2 = a.oNext(); - QuadEdge t3 = beta.oNext(); - QuadEdge t4 = alpha.oNext(); - - a.setNext(t1); - b.setNext(t2); - alpha.setNext(t3); - beta.setNext(t4); - } - - /** - * Turns an edge counterclockwise inside its enclosing quadrilateral. - * - * @param e the quadedge to turn - */ - public static void swap(QuadEdge e) { - QuadEdge a = e.oPrev(); - QuadEdge b = e.sym().oPrev(); - splice(e, a); - splice(e.sym(), b); - splice(e, a.lNext()); - splice(e.sym(), b.lNext()); - e.setOrig(a.dest()); - e.setDest(b.dest()); - } - - // the dual of this edge, directed from right to left - private QuadEdge rot; - private Vertex vertex; // The vertex that this edge represents - private QuadEdge next; // A reference to a connected edge - private Object data = null; -// private int visitedKey = 0; - - /** - * Quadedges must be made using {@link makeEdge}, - * to ensure proper construction. - */ - private QuadEdge() - { - - } - - /** - * Gets the primary edge of this quadedge and its sym. - * The primary edge is the one for which the origin - * and destination coordinates are ordered - * according to the standard {@link Coordinate} ordering - * - * @return the primary quadedge - */ - public QuadEdge getPrimary() - { - if (orig().getCoordinate().compareTo(dest().getCoordinate()) <= 0) - return this; - else - return sym(); - } - - /** - * Sets the external data value for this edge. - * - * @param data an object containing external data - */ - public void setData(Object data) { - this.data = data; - } - - /** - * Gets the external data value for this edge. - * - * @return the data object - */ - public Object getData() { - return data; - } - - /** - * Marks this quadedge as being deleted. - * This does not free the memory used by - * this quadedge quartet, but indicates - * that this edge no longer participates - * in a subdivision. - * - */ - public void delete() { - rot = null; - } - - /** - * Tests whether this edge has been deleted. - * - * @return true if this edge has not been deleted. - */ - public boolean isLive() { - return rot != null; - } - - - /** - * Sets the connected edge - * - * @param next edge - */ - public void setNext(QuadEdge next) { - this.next = next; - } - - /*************************************************************************** - * QuadEdge Algebra - *************************************************************************** - */ - - /** - * Gets the dual of this edge, directed from its right to its left. - * - * @return the rotated edge - */ - public final QuadEdge rot() { - return rot; - } - - /** - * Gets the dual of this edge, directed from its left to its right. - * - * @return the inverse rotated edge. - */ - public final QuadEdge invRot() { - return rot.sym(); - } - - /** - * Gets the edge from the destination to the origin of this edge. - * - * @return the sym of the edge - */ - public final QuadEdge sym() { - return rot.rot; - } - - /** - * Gets the next CCW edge around the origin of this edge. - * - * @return the next linked edge. - */ - public final QuadEdge oNext() { - return next; - } - - /** - * Gets the next CW edge around (from) the origin of this edge. - * - * @return the previous edge. - */ - public final QuadEdge oPrev() { - return rot.next.rot; - } - - /** - * Gets the next CCW edge around (into) the destination of this edge. - * - * @return the next destination edge. - */ - public final QuadEdge dNext() { - return this.sym().oNext().sym(); - } - - /** - * Gets the next CW edge around (into) the destination of this edge. - * - * @return the previous destination edge. - */ - public final QuadEdge dPrev() { - return this.invRot().oNext().invRot(); - } - - /** - * Gets the CCW edge around the left face following this edge. - * - * @return the next left face edge. - */ - public final QuadEdge lNext() { - return this.invRot().oNext().rot(); - } - - /** - * Gets the CCW edge around the left face before this edge. - * - * @return the previous left face edge. - */ - public final QuadEdge lPrev() { - return next.sym(); - } - - /** - * Gets the edge around the right face ccw following this edge. - * - * @return the next right face edge. - */ - public final QuadEdge rNext() { - return rot.next.invRot(); - } - - /** - * Gets the edge around the right face ccw before this edge. - * - * @return the previous right face edge. - */ - public final QuadEdge rPrev() { - return this.sym().oNext(); - } - - /*********************************************************************************************** - * Data Access - **********************************************************************************************/ - /** - * Sets the vertex for this edge's origin - * - * @param o the origin vertex - */ - void setOrig(Vertex o) { - vertex = o; - } - - /** - * Sets the vertex for this edge's destination - * - * @param d the destination vertex - */ - void setDest(Vertex d) { - sym().setOrig(d); - } - - /** - * Gets the vertex for the edge's origin - * - * @return the origin vertex - */ - public final Vertex orig() { - return vertex; - } - - /** - * Gets the vertex for the edge's destination - * - * @return the destination vertex - */ - public final Vertex dest() { - return sym().orig(); - } - - /** - * Gets the length of the geometry of this quadedge. - * - * @return the length of the quadedge - */ - public double getLength() { - return orig().getCoordinate().distance(dest().getCoordinate()); - } - - /** - * Tests if this quadedge and another have the same line segment geometry, - * regardless of orientation. - * - * @param qe a quadege - * @return true if the quadedges are based on the same line segment regardless of orientation - */ - public boolean equalsNonOriented(QuadEdge qe) { - if (equalsOriented(qe)) - return true; - if (equalsOriented(qe.sym())) - return true; - return false; - } - - /** - * Tests if this quadedge and another have the same line segment geometry - * with the same orientation. - * - * @param qe a quadege - * @return true if the quadedges are based on the same line segment - */ - public boolean equalsOriented(QuadEdge qe) { - if (orig().getCoordinate().equals2D(qe.orig().getCoordinate()) - && dest().getCoordinate().equals2D(qe.dest().getCoordinate())) - return true; - return false; - } - - /** - * Creates a {@link LineSegment} representing the - * geometry of this edge. - * - * @return a LineSegment - */ - public LineSegment toLineSegment() - { - return new LineSegment(vertex.getCoordinate(), dest().getCoordinate()); - } - - /** - * Converts this edge to a WKT two-point LINESTRING indicating - * the geometry of this edge. - * - * @return a String representing this edge's geometry - */ - public String toString() { - Coordinate p0 = vertex.getCoordinate(); - Coordinate p1 = dest().getCoordinate(); - return WKTWriter.toLineString(p0, p1); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeLocator.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeLocator.java deleted file mode 100644 index 24480f3a28..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeLocator.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -/** - * An interface for classes which locate an edge in a {@link QuadEdgeSubdivision} - * which either contains a given {@link Vertex} V - * or is an edge of a triangle which contains V. - * Implementors may utilized different strategies for - * optimizing locating containing edges/triangles. - * - * @author Martin Davis - */ -public interface QuadEdgeLocator { - QuadEdge locate(Vertex v); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java deleted file mode 100644 index a03fc6b719..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java +++ /dev/null @@ -1,954 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import java.util.*; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.io.WKTWriter; - -/** - * A class that contains the {@link QuadEdge}s representing a planar - * subdivision that models a triangulation. - * The subdivision is constructed using the - * quadedge algebra defined in the classs {@link QuadEdge}. - * All metric calculations - * are done in the {@link Vertex} class. - * In addition to a triangulation, subdivisions - * support extraction of Voronoi diagrams. - * This is easily accomplished, since the Voronoi diagram is the dual - * of the Delaunay triangulation. - *

                        - * Subdivisions can be provided with a tolerance value. Inserted vertices which - * are closer than this value to vertices already in the subdivision will be - * ignored. Using a suitable tolerance value can prevent robustness failures - * from happening during Delaunay triangulation. - *

                        - * Subdivisions maintain a frame triangle around the client-created - * edges. The frame is used to provide a bounded "container" for all edges - * within a TIN. Normally the frame edges, frame connecting edges, and frame - * triangles are not included in client processing. - * - * @author David Skea - * @author Martin Davis - */ -public class QuadEdgeSubdivision { - /** - * Gets the edges for the triangle to the left of the given {@link QuadEdge}. - * - * @param startQE - * @param triEdge - * - * @throws IllegalArgumentException - * if the edges do not form a triangle - */ - public static void getTriangleEdges(QuadEdge startQE, QuadEdge[] triEdge) { - triEdge[0] = startQE; - triEdge[1] = triEdge[0].lNext(); - triEdge[2] = triEdge[1].lNext(); - if (triEdge[2].lNext() != triEdge[0]) - throw new IllegalArgumentException("Edges do not form a triangle"); - } - - private final static double EDGE_COINCIDENCE_TOL_FACTOR = 1000; - - // debugging only - preserve current subdiv statically - // private static QuadEdgeSubdivision currentSubdiv; - - // used for edge extraction to ensure edge uniqueness - private int visitedKey = 0; -// private Set quadEdges = new HashSet(); - private List quadEdges = new ArrayList(); - private QuadEdge startingEdge; - private double tolerance; - private double edgeCoincidenceTolerance; - private Vertex[] frameVertex = new Vertex[3]; - private Envelope frameEnv; - private QuadEdgeLocator locator = null; - - /** - * Creates a new instance of a quad-edge subdivision based on a frame triangle - * that encloses a supplied bounding box. A new super-bounding box that - * contains the triangle is computed and stored. - * - * @param env - * the bouding box to surround - * @param tolerance - * the tolerance value for determining if two sites are equal - */ - public QuadEdgeSubdivision(Envelope env, double tolerance) { - // currentSubdiv = this; - this.tolerance = tolerance; - edgeCoincidenceTolerance = tolerance / EDGE_COINCIDENCE_TOL_FACTOR; - - createFrame(env); - - startingEdge = initSubdiv(); - locator = new LastFoundQuadEdgeLocator(this); - } - - private void createFrame(Envelope env) - { - double deltaX = env.getWidth(); - double deltaY = env.getHeight(); - double offset = 0.0; - if (deltaX > deltaY) { - offset = deltaX * 10.0; - } else { - offset = deltaY * 10.0; - } - - frameVertex[0] = new Vertex((env.getMaxX() + env.getMinX()) / 2.0, env - .getMaxY() - + offset); - frameVertex[1] = new Vertex(env.getMinX() - offset, env.getMinY() - offset); - frameVertex[2] = new Vertex(env.getMaxX() + offset, env.getMinY() - offset); - - frameEnv = new Envelope(frameVertex[0].getCoordinate(), frameVertex[1] - .getCoordinate()); - frameEnv.expandToInclude(frameVertex[2].getCoordinate()); - } - - private QuadEdge initSubdiv() - { - // build initial subdivision from frame - QuadEdge ea = makeEdge(frameVertex[0], frameVertex[1]); - QuadEdge eb = makeEdge(frameVertex[1], frameVertex[2]); - QuadEdge.splice(ea.sym(), eb); - QuadEdge ec = makeEdge(frameVertex[2], frameVertex[0]); - QuadEdge.splice(eb.sym(), ec); - QuadEdge.splice(ec.sym(), ea); - return ea; - } - - /** - * Gets the vertex-equality tolerance value - * used in this subdivision - * - * @return the tolerance value - */ - public double getTolerance() { - return tolerance; - } - - /** - * Gets the envelope of the Subdivision (including the frame). - * - * @return the envelope - */ - public Envelope getEnvelope() { - return new Envelope(frameEnv); - } - - /** - * Gets the collection of base {@link QuadEdge}s (one for every pair of - * vertices which is connected). - * - * @return a collection of QuadEdges - */ - public Collection getEdges() { - return quadEdges; - } - - /** - * Sets the {@link QuadEdgeLocator} to use for locating containing triangles - * in this subdivision. - * - * @param locator - * a QuadEdgeLocator - */ - public void setLocator(QuadEdgeLocator locator) { - this.locator = locator; - } - - /** - * Creates a new quadedge, recording it in the edges list. - * - * @param o - * @param d - * @return a new quadedge - */ - public QuadEdge makeEdge(Vertex o, Vertex d) { - QuadEdge q = QuadEdge.makeEdge(o, d); - quadEdges.add(q); - return q; - } - - /** - * Creates a new QuadEdge connecting the destination of a to the origin of b, - * in such a way that all three have the same left face after the connection - * is complete. The quadedge is recorded in the edges list. - * - * @param a - * @param b - * @return a quadedge - */ - public QuadEdge connect(QuadEdge a, QuadEdge b) { - QuadEdge q = QuadEdge.connect(a, b); - quadEdges.add(q); - return q; - } - - /** - * Deletes a quadedge from the subdivision. Linked quadedges are updated to - * reflect the deletion. - * - * @param e - * the quadedge to delete - */ - public void delete(QuadEdge e) { - QuadEdge.splice(e, e.oPrev()); - QuadEdge.splice(e.sym(), e.sym().oPrev()); - - QuadEdge eSym = e.sym(); - QuadEdge eRot = e.rot(); - QuadEdge eRotSym = e.rot().sym(); - - // this is inefficient on an ArrayList, but this method should be called infrequently - quadEdges.remove(e); - quadEdges.remove(eSym); - quadEdges.remove(eRot); - quadEdges.remove(eRotSym); - - e.delete(); - eSym.delete(); - eRot.delete(); - eRotSym.delete(); - } - - /** - * Locates an edge of a triangle which contains a location - * specified by a Vertex v. - * The edge returned has the - * property that either v is on e, or e is an edge of a triangle containing v. - * The search starts from startEdge amd proceeds on the general direction of v. - *

                        - * This locate algorithm relies on the subdivision being Delaunay. For - * non-Delaunay subdivisions, this may loop for ever. - * - * @param v the location to search for - * @param startEdge an edge of the subdivision to start searching at - * @returns a QuadEdge which contains v, or is on the edge of a triangle containing v - * @throws LocateFailureException - * if the location algorithm fails to converge in a reasonable - * number of iterations - */ - public QuadEdge locateFromEdge(Vertex v, QuadEdge startEdge) { - int iter = 0; - int maxIter = quadEdges.size(); - - QuadEdge e = startEdge; - - while (true) { - iter++; - - /** - * So far it has always been the case that failure to locate indicates an - * invalid subdivision. So just fail completely. (An alternative would be - * to perform an exhaustive search for the containing triangle, but this - * would mask errors in the subdivision topology) - * - * This can also happen if two vertices are located very close together, - * since the orientation predicates may experience precision failures. - */ - if (iter > maxIter) { - throw new LocateFailureException(e.toLineSegment()); - // String msg = "Locate failed to converge (at edge: " + e + "). - // Possible causes include invalid Subdivision topology or very close - // sites"; - // System.err.println(msg); - // dumpTriangles(); - } - - if ((v.equals(e.orig())) || (v.equals(e.dest()))) { - break; - } else if (v.rightOf(e)) { - e = e.sym(); - } else if (!v.rightOf(e.oNext())) { - e = e.oNext(); - } else if (!v.rightOf(e.dPrev())) { - e = e.dPrev(); - } else { - // on edge or in triangle containing edge - break; - } - } - // System.out.println("Locate count: " + iter); - return e; - } - - /** - * Finds a quadedge of a triangle containing a location - * specified by a {@link Vertex}, if one exists. - * - * @param v the vertex to locate - * @return a quadedge on the edge of a triangle which touches or contains the location - * or null if no such triangle exists - */ - public QuadEdge locate(Vertex v) { - return locator.locate(v); - } - - /** - * Finds a quadedge of a triangle containing a location - * specified by a {@link Coordinate}, if one exists. - * - * @param p the Coordinate to locate - * @return a quadedge on the edge of a triangle which touches or contains the location - * or null if no such triangle exists - */ - public QuadEdge locate(Coordinate p) { - return locator.locate(new Vertex(p)); - } - - /** - * Locates the edge between the given vertices, if it exists in the - * subdivision. - * - * @param p0 a coordinate - * @param p1 another coordinate - * @return the edge joining the coordinates, if present - * or null if no such edge exists - */ - public QuadEdge locate(Coordinate p0, Coordinate p1) { - // find an edge containing one of the points - QuadEdge e = locator.locate(new Vertex(p0)); - if (e == null) - return null; - - // normalize so that p0 is origin of base edge - QuadEdge base = e; - if (e.dest().getCoordinate().equals2D(p0)) - base = e.sym(); - // check all edges around origin of base edge - QuadEdge locEdge = base; - do { - if (locEdge.dest().getCoordinate().equals2D(p1)) - return locEdge; - locEdge = locEdge.oNext(); - } while (locEdge != base); - return null; - } - - /** - * Inserts a new site into the Subdivision, connecting it to the vertices of - * the containing triangle (or quadrilateral, if the split point falls on an - * existing edge). - *

                        - * This method does NOT maintain the Delaunay condition. If desired, this must - * be checked and enforced by the caller. - *

                        - * This method does NOT check if the inserted vertex falls on an edge. This - * must be checked by the caller, since this situation may cause erroneous - * triangulation - * - * @param v - * the vertex to insert - * @return a new quad edge terminating in v - */ - public QuadEdge insertSite(Vertex v) { - QuadEdge e = locate(v); - - if ((v.equals(e.orig(), tolerance)) || (v.equals(e.dest(), tolerance))) { - return e; // point already in subdivision. - } - - // Connect the new point to the vertices of the containing - // triangle (or quadrilateral, if the new point fell on an - // existing edge.) - QuadEdge base = makeEdge(e.orig(), v); - QuadEdge.splice(base, e); - QuadEdge startEdge = base; - do { - base = connect(e, base.sym()); - e = base.oPrev(); - } while (e.lNext() != startEdge); - - return startEdge; - } - - /** - * Tests whether a QuadEdge is an edge incident on a frame triangle vertex. - * - * @param e - * the edge to test - * @return true if the edge is connected to the frame triangle - */ - public boolean isFrameEdge(QuadEdge e) { - if (isFrameVertex(e.orig()) || isFrameVertex(e.dest())) - return true; - return false; - } - - /** - * Tests whether a QuadEdge is an edge on the border of the frame facets and - * the internal facets. E.g. an edge which does not itself touch a frame - * vertex, but which touches an edge which does. - * - * @param e - * the edge to test - * @return true if the edge is on the border of the frame - */ - public boolean isFrameBorderEdge(QuadEdge e) { - // MD debugging - QuadEdge[] leftTri = new QuadEdge[3]; - getTriangleEdges(e, leftTri); - // System.out.println(new QuadEdgeTriangle(leftTri).toString()); - QuadEdge[] rightTri = new QuadEdge[3]; - getTriangleEdges(e.sym(), rightTri); - // System.out.println(new QuadEdgeTriangle(rightTri).toString()); - - // check other vertex of triangle to left of edge - Vertex vLeftTriOther = e.lNext().dest(); - if (isFrameVertex(vLeftTriOther)) - return true; - // check other vertex of triangle to right of edge - Vertex vRightTriOther = e.sym().lNext().dest(); - if (isFrameVertex(vRightTriOther)) - return true; - - return false; - } - - /** - * Tests whether a vertex is a vertex of the outer triangle. - * - * @param v - * the vertex to test - * @return true if the vertex is an outer triangle vertex - */ - public boolean isFrameVertex(Vertex v) { - if (v.equals(frameVertex[0])) - return true; - if (v.equals(frameVertex[1])) - return true; - if (v.equals(frameVertex[2])) - return true; - return false; - } - - private LineSegment seg = new LineSegment(); - - /** - * Tests whether a {@link Coordinate} lies on a {@link QuadEdge}, up to a - * tolerance determined by the subdivision tolerance. - * - * @param e - * a QuadEdge - * @param p - * a point - * @return true if the vertex lies on the edge - */ - public boolean isOnEdge(QuadEdge e, Coordinate p) { - seg.setCoordinates(e.orig().getCoordinate(), e.dest().getCoordinate()); - double dist = seg.distance(p); - // heuristic (hack?) - return dist < edgeCoincidenceTolerance; - } - - /** - * Tests whether a {@link Vertex} is the start or end vertex of a - * {@link QuadEdge}, up to the subdivision tolerance distance. - * - * @param e - * @param v - * @return true if the vertex is a endpoint of the edge - */ - public boolean isVertexOfEdge(QuadEdge e, Vertex v) { - if ((v.equals(e.orig(), tolerance)) || (v.equals(e.dest(), tolerance))) { - return true; - } - return false; - } - - /** - * Gets the unique {@link Vertex}es in the subdivision, - * including the frame vertices if desired. - * - * @param includeFrame - * true if the frame vertices should be included - * @return a collection of the subdivision vertices - * - * @see #getVertexUniqueEdges - */ - public Collection getVertices(boolean includeFrame) - { - Set vertices = new HashSet(); - for (Iterator i = quadEdges.iterator(); i.hasNext();) { - QuadEdge qe = (QuadEdge) i.next(); - Vertex v = qe.orig(); - //System.out.println(v); - if (includeFrame || ! isFrameVertex(v)) - vertices.add(v); - - /** - * Inspect the sym edge as well, since it is - * possible that a vertex is only at the - * dest of all tracked quadedges. - */ - Vertex vd = qe.dest(); - //System.out.println(vd); - if (includeFrame || ! isFrameVertex(vd)) - vertices.add(vd); - } - return vertices; - } - - /** - * Gets a collection of {@link QuadEdge}s whose origin - * vertices are a unique set which includes - * all vertices in the subdivision. - * The frame vertices can be included if required. - *

                        - * This is useful for algorithms which require traversing the - * subdivision starting at all vertices. - * Returning a quadedge for each vertex - * is more efficient than - * the alternative of finding the actual vertices - * using {@link #getVertices} and then locating - * quadedges attached to them. - * - * @param includeFrame true if the frame vertices should be included - * @return a collection of QuadEdge with the vertices of the subdivision as their origins - */ - public List getVertexUniqueEdges(boolean includeFrame) - { - List edges = new ArrayList(); - Set visitedVertices = new HashSet(); - for (Iterator i = quadEdges.iterator(); i.hasNext();) { - QuadEdge qe = (QuadEdge) i.next(); - Vertex v = qe.orig(); - //System.out.println(v); - if (! visitedVertices.contains(v)) { - visitedVertices.add(v); - if (includeFrame || ! isFrameVertex(v)) { - edges.add(qe); - } - } - - /** - * Inspect the sym edge as well, since it is - * possible that a vertex is only at the - * dest of all tracked quadedges. - */ - QuadEdge qd = qe.sym(); - Vertex vd = qd.orig(); - //System.out.println(vd); - if (! visitedVertices.contains(vd)) { - visitedVertices.add(vd); - if (includeFrame || ! isFrameVertex(vd)) { - edges.add(qd); - } - } - } - return edges; - } - - /** - * Gets all primary quadedges in the subdivision. - * A primary edge is a {@link QuadEdge} - * which occupies the 0'th position in its array of associated quadedges. - * These provide the unique geometric edges of the triangulation. - * - * @param includeFrame true if the frame edges are to be included - * @return a List of QuadEdges - */ - public List getPrimaryEdges(boolean includeFrame) { - visitedKey++; - - List edges = new ArrayList(); - Stack edgeStack = new Stack(); - edgeStack.push(startingEdge); - - Set visitedEdges = new HashSet(); - - while (!edgeStack.empty()) { - QuadEdge edge = (QuadEdge) edgeStack.pop(); - if (! visitedEdges.contains(edge)) { - QuadEdge priQE = edge.getPrimary(); - - if (includeFrame || ! isFrameEdge(priQE)) - edges.add(priQE); - - edgeStack.push(edge.oNext()); - edgeStack.push(edge.sym().oNext()); - - visitedEdges.add(edge); - visitedEdges.add(edge.sym()); - } - } - return edges; - } - - /** - * A TriangleVisitor which computes and sets the - * circumcentre as the origin of the dual - * edges originating in each triangle. - * - * @author mbdavis - * - */ - private static class TriangleCircumcentreVisitor implements TriangleVisitor - { - public TriangleCircumcentreVisitor() { - } - - public void visit(QuadEdge[] triEdges) - { - Coordinate a = triEdges[0].orig().getCoordinate(); - Coordinate b = triEdges[1].orig().getCoordinate(); - Coordinate c = triEdges[2].orig().getCoordinate(); - - // TODO: choose the most accurate circumcentre based on the edges - Coordinate cc = Triangle.circumcentre(a, b, c); - Vertex ccVertex = new Vertex(cc); - // save the circumcentre as the origin for the dual edges originating in this triangle - for (int i = 0; i < 3; i++) { - triEdges[i].rot().setOrig(ccVertex); - } - } - } - - /***************************************************************************** - * Visitors - ****************************************************************************/ - - public void visitTriangles(TriangleVisitor triVisitor, - boolean includeFrame) { - visitedKey++; - - // visited flag is used to record visited edges of triangles - // setVisitedAll(false); - Stack edgeStack = new Stack(); - edgeStack.push(startingEdge); - - Set visitedEdges = new HashSet(); - - while (!edgeStack.empty()) { - QuadEdge edge = (QuadEdge) edgeStack.pop(); - if (! visitedEdges.contains(edge)) { - QuadEdge[] triEdges = fetchTriangleToVisit(edge, edgeStack, - includeFrame, visitedEdges); - if (triEdges != null) - triVisitor.visit(triEdges); - } - } - } - - /** - * The quadedges forming a single triangle. - * Only one visitor is allowed to be active at a - * time, so this is safe. - */ - private QuadEdge[] triEdges = new QuadEdge[3]; - - /** - * Stores the edges for a visited triangle. Also pushes sym (neighbour) edges - * on stack to visit later. - * - * @param edge - * @param edgeStack - * @param includeFrame - * @return the visited triangle edges - * or null if the triangle should not be visited (for instance, if it is - * outer) - */ - private QuadEdge[] fetchTriangleToVisit(QuadEdge edge, Stack edgeStack, - boolean includeFrame, Set visitedEdges) { - QuadEdge curr = edge; - int edgeCount = 0; - boolean isFrame = false; - do { - triEdges[edgeCount] = curr; - - if (isFrameEdge(curr)) - isFrame = true; - - // push sym edges to visit next - QuadEdge sym = curr.sym(); - if (! visitedEdges.contains(sym)) - edgeStack.push(sym); - - // mark this edge as visited - visitedEdges.add(curr); - - edgeCount++; - curr = curr.lNext(); - } while (curr != edge); - - if (isFrame && !includeFrame) - return null; - return triEdges; - } - - /** - * Gets a list of the triangles - * in the subdivision, specified as - * an array of the primary quadedges around the triangle. - * - * @param includeFrame - * true if the frame triangles should be included - * @return a List of QuadEdge[3] arrays - */ - public List getTriangleEdges(boolean includeFrame) { - TriangleEdgesListVisitor visitor = new TriangleEdgesListVisitor(); - visitTriangles(visitor, includeFrame); - return visitor.getTriangleEdges(); - } - - private static class TriangleEdgesListVisitor implements TriangleVisitor { - private List triList = new ArrayList(); - - public void visit(QuadEdge[] triEdges) { - triList.add(triEdges.clone()); - } - - public List getTriangleEdges() { - return triList; - } - } - - /** - * Gets a list of the triangles in the subdivision, - * specified as an array of the triangle {@link Vertex}es. - * - * @param includeFrame - * true if the frame triangles should be included - * @return a List of Vertex[3] arrays - */ - public List getTriangleVertices(boolean includeFrame) { - TriangleVertexListVisitor visitor = new TriangleVertexListVisitor(); - visitTriangles(visitor, includeFrame); - return visitor.getTriangleVertices(); - } - - private static class TriangleVertexListVisitor implements TriangleVisitor { - private List triList = new ArrayList(); - - public void visit(QuadEdge[] triEdges) { - triList.add(new Vertex[] { triEdges[0].orig(), triEdges[1].orig(), - triEdges[2].orig() }); - } - - public List getTriangleVertices() { - return triList; - } - } - - /** - * Gets the coordinates for each triangle in the subdivision as an array. - * - * @param includeFrame - * true if the frame triangles should be included - * @return a list of Coordinate[4] representing each triangle - */ - public List getTriangleCoordinates(boolean includeFrame) { - TriangleCoordinatesVisitor visitor = new TriangleCoordinatesVisitor(); - visitTriangles(visitor, includeFrame); - return visitor.getTriangles(); - } - - private static class TriangleCoordinatesVisitor implements TriangleVisitor { - private CoordinateList coordList = new CoordinateList(); - - private List triCoords = new ArrayList(); - - public TriangleCoordinatesVisitor() { - } - - public void visit(QuadEdge[] triEdges) { - coordList.clear(); - for (int i = 0; i < 3; i++) { - Vertex v = triEdges[i].orig(); - coordList.add(v.getCoordinate()); - } - if (coordList.size() > 0) { - coordList.closeRing(); - Coordinate[] pts = coordList.toCoordinateArray(); - if (pts.length != 4) { - //checkTriangleSize(pts); - return; - } - - triCoords.add(pts); - } - } - - private void checkTriangleSize(Coordinate[] pts) - { - String loc = ""; - if (pts.length >= 2) - loc = WKTWriter.toLineString(pts[0], pts[1]); - else { - if (pts.length >= 1) - loc = WKTWriter.toPoint(pts[0]); - } - // Assert.isTrue(pts.length == 4, "Too few points for visited triangle at " + loc); - //com.vividsolutions.jts.util.Debug.println("too few points for triangle at " + loc); - } - - public List getTriangles() { - return triCoords; - } - } - - /** - * Gets the geometry for the edges in the subdivision as a {@link MultiLineString} - * containing 2-point lines. - * - * @param geomFact the GeometryFactory to use - * @return a MultiLineString - */ - public Geometry getEdges(GeometryFactory geomFact) { - List quadEdges = getPrimaryEdges(false); - LineString[] edges = new LineString[quadEdges.size()]; - int i = 0; - for (Iterator it = quadEdges.iterator(); it.hasNext();) { - QuadEdge qe = (QuadEdge) it.next(); - edges[i++] = geomFact.createLineString(new Coordinate[] { - qe.orig().getCoordinate(), qe.dest().getCoordinate() }); - } - return geomFact.createMultiLineString(edges); - } - - /** - * Gets the geometry for the triangles in a triangulated subdivision as a {@link GeometryCollection} - * of triangular {@link Polygon}s. - * - * @param geomFact the GeometryFactory to use - * @return a GeometryCollection of triangular Polygons - */ - public Geometry getTriangles(GeometryFactory geomFact) { - List triPtsList = getTriangleCoordinates(false); - Polygon[] tris = new Polygon[triPtsList.size()]; - int i = 0; - for (Iterator it = triPtsList.iterator(); it.hasNext();) { - Coordinate[] triPt = (Coordinate[]) it.next(); - tris[i++] = geomFact - .createPolygon(geomFact.createLinearRing(triPt), null); - } - return geomFact.createGeometryCollection(tris); - } - - /** - * Gets the cells in the Voronoi diagram for this triangulation. - * The cells are returned as a {@link GeometryCollection} of {@link Polygon}s - *

                        - * The userData of each polygon is set to be the {@link Coordinate} - * of the cell site. This allows easily associating external - * data associated with the sites to the cells. - * - * @param geomFact a geometry factory - * @return a GeometryCollection of Polygons - */ - public Geometry getVoronoiDiagram(GeometryFactory geomFact) - { - List vorCells = getVoronoiCellPolygons(geomFact); - return geomFact.createGeometryCollection(GeometryFactory.toGeometryArray(vorCells)); - } - - /** - * Gets a List of {@link Polygon}s for the Voronoi cells - * of this triangulation. - *

                        - * The userData of each polygon is set to be the {@link Coordinate} - * of the cell site. This allows easily associating external - * data associated with the sites to the cells. - * - * @param geomFact a geometry factory - * @return a List of Polygons - */ - public List getVoronoiCellPolygons(GeometryFactory geomFact) - { - /* - * Compute circumcentres of triangles as vertices for dual edges. - * Precomputing the circumcentres is more efficient, - * and more importantly ensures that the computed centres - * are consistent across the Voronoi cells. - */ - visitTriangles(new TriangleCircumcentreVisitor(), true); - - List cells = new ArrayList(); - Collection edges = getVertexUniqueEdges(false); - for (Iterator i = edges.iterator(); i.hasNext(); ) { - QuadEdge qe = (QuadEdge) i.next(); - cells.add(getVoronoiCellPolygon(qe, geomFact)); - } - return cells; - } - - /** - * Gets the Voronoi cell around a site specified - * by the origin of a QuadEdge. - *

                        - * The userData of the polygon is set to be the {@link Coordinate} - * of the site. This allows attaching external - * data associated with the site to this cell polygon. - * - * @param qe a quadedge originating at the cell site - * @param geomFact a factory for building the polygon - * @return a polygon indicating the cell extent - */ - public Polygon getVoronoiCellPolygon(QuadEdge qe, GeometryFactory geomFact) - { - List cellPts = new ArrayList(); - QuadEdge startQE = qe; - do { -// Coordinate cc = circumcentre(qe); - // use previously computed circumcentre - Coordinate cc = qe.rot().orig().getCoordinate(); - cellPts.add(cc); - - // move to next triangle CW around vertex - qe = qe.oPrev(); - } while (qe != startQE); - - CoordinateList coordList = new CoordinateList(); - coordList.addAll(cellPts, false); - coordList.closeRing(); - - if (coordList.size() < 4) { - System.out.println(coordList); - coordList.add(coordList.get(coordList.size()-1), true); - } - - Coordinate[] pts = coordList.toCoordinateArray(); - Polygon cellPoly = geomFact.createPolygon(geomFact.createLinearRing(pts), null); - - Vertex v = startQE.orig(); - cellPoly.setUserData(v.getCoordinate()); - return cellPoly; - } - -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java deleted file mode 100644 index daa19240d5..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.algorithm.CGAlgorithms; -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineSegment; -import com.vividsolutions.jts.geom.LinearRing; -import com.vividsolutions.jts.geom.Polygon; - -/** - * Models a triangle formed from {@link QuadEdge}s in a {@link QuadEdgeSubdivision} - * which forms a triangulation. The class provides methods to access the - * topological and geometric properties of the triangle and its neighbours in - * the triangulation. Triangle vertices are ordered in CCW orientation in the - * structure. - *

                        - * QuadEdgeTriangles support having an external data attribute attached to them. - * Alternatively, this class can be subclassed and attributes can - * be defined in the subclass. Subclasses will need to define - * their own BuilderVisitor class - * and createOn method. - * - * @author Martin Davis - * @version 1.0 - */ -public class QuadEdgeTriangle -{ - /** - * Creates {@link QuadEdgeTriangle}s for all facets of a - * {@link QuadEdgeSubdivision} representing a triangulation. - * The data attributes of the {@link QuadEdge}s in the subdivision - * will be set to point to the triangle which contains that edge. - * This allows tracing the neighbour triangles of any given triangle. - * - * @param subdiv - * the QuadEdgeSubdivision to create the triangles on. - * @return a List of the created QuadEdgeTriangles - */ - public static List createOn(QuadEdgeSubdivision subdiv) - { - QuadEdgeTriangleBuilderVisitor visitor = new QuadEdgeTriangleBuilderVisitor(); - subdiv.visitTriangles(visitor, false); - return visitor.getTriangles(); - } - - /** - * Tests whether the point pt is contained in the triangle defined by 3 - * {@link Vertex}es. - * - * @param tri - * an array containing at least 3 Vertexes - * @param pt - * the point to test - * @return true if the point is contained in the triangle - */ - public static boolean contains(Vertex[] tri, Coordinate pt) { - Coordinate[] ring = new Coordinate[] { tri[0].getCoordinate(), - tri[1].getCoordinate(), tri[2].getCoordinate(), tri[0].getCoordinate() }; - return CGAlgorithms.isPointInRing(pt, ring); - } - - /** - * Tests whether the point pt is contained in the triangle defined by 3 - * {@link QuadEdge}es. - * - * @param tri - * an array containing at least 3 QuadEdges - * @param pt - * the point to test - * @return true if the point is contained in the triangle - */ - public static boolean contains(QuadEdge[] tri, Coordinate pt) { - Coordinate[] ring = new Coordinate[] { tri[0].orig().getCoordinate(), - tri[1].orig().getCoordinate(), tri[2].orig().getCoordinate(), - tri[0].orig().getCoordinate() }; - return CGAlgorithms.isPointInRing(pt, ring); - } - - public static Geometry toPolygon(Vertex[] v) { - Coordinate[] ringPts = new Coordinate[] { v[0].getCoordinate(), - v[1].getCoordinate(), v[2].getCoordinate(), v[0].getCoordinate() }; - GeometryFactory fact = new GeometryFactory(); - LinearRing ring = fact.createLinearRing(ringPts); - Polygon tri = fact.createPolygon(ring, null); - return tri; - } - - public static Geometry toPolygon(QuadEdge[] e) { - Coordinate[] ringPts = new Coordinate[] { e[0].orig().getCoordinate(), - e[1].orig().getCoordinate(), e[2].orig().getCoordinate(), - e[0].orig().getCoordinate() }; - GeometryFactory fact = new GeometryFactory(); - LinearRing ring = fact.createLinearRing(ringPts); - Polygon tri = fact.createPolygon(ring, null); - return tri; - } - - /** - * Finds the next index around the triangle. Index may be an edge or vertex - * index. - * - * @param index - * @return the next index - */ - public static int nextIndex(int index) { - return index = (index + 1) % 3; - } - - private QuadEdge[] edge; - private Object data; - - /** - * Creates a new triangle from the given edges. - * - * @param edge an array of the edges of the triangle in CCW order - */ - public QuadEdgeTriangle(QuadEdge[] edge) { - this.edge = (QuadEdge[]) edge.clone(); - // link the quadedges back to this triangle - for (int i = 0; i < 3; i++) { - edge[i].setData(this); - } - } - - /** - * Sets the external data value for this triangle. - * - * @param data an object containing external data - */ - public void setData(Object data) { - this.data = data; - } - - /** - * Gets the external data value for this triangle. - * - * @return the data object - */ - public Object getData() { - return data; - } - - public void kill() { - edge = null; - } - - public boolean isLive() { - return edge != null; - } - - public QuadEdge[] getEdges() { - return edge; - } - - public QuadEdge getEdge(int i) { - return edge[i]; - } - - public Vertex getVertex(int i) { - return edge[i].orig(); - } - - /** - * Gets the vertices for this triangle. - * - * @return a new array containing the triangle vertices - */ - public Vertex[] getVertices() { - Vertex[] vert = new Vertex[3]; - for (int i = 0; i < 3; i++) { - vert[i] = getVertex(i); - } - return vert; - } - - public Coordinate getCoordinate(int i) { - return edge[i].orig().getCoordinate(); - } - - /** - * Gets the index for the given edge of this triangle - * - * @param e - * a QuadEdge - * @return the index of the edge in this triangle - * or -1 if the edge is not an edge of this triangle - */ - public int getEdgeIndex(QuadEdge e) { - for (int i = 0; i < 3; i++) { - if (edge[i] == e) - return i; - } - return -1; - } - - /** - * Gets the index for the edge that starts at vertex v. - * - * @param v - * the vertex to find the edge for - * @return the index of the edge starting at the vertex - * or -1 if the vertex is not in the triangle - */ - public int getEdgeIndex(Vertex v) { - for (int i = 0; i < 3; i++) { - if (edge[i].orig() == v) - return i; - } - return -1; - } - - public void getEdgeSegment(int i, LineSegment seg) { - seg.p0 = edge[i].orig().getCoordinate(); - int nexti = (i + 1) % 3; - seg.p1 = edge[nexti].orig().getCoordinate(); - } - - public Coordinate[] getCoordinates() { - Coordinate[] pts = new Coordinate[4]; - for (int i = 0; i < 3; i++) { - pts[i] = edge[i].orig().getCoordinate(); - } - pts[3] = new Coordinate(pts[0]); - return pts; - } - - public boolean contains(Coordinate pt) { - Coordinate[] ring = getCoordinates(); - return CGAlgorithms.isPointInRing(pt, ring); - } - - public Polygon getGeometry(GeometryFactory fact) { - LinearRing ring = fact.createLinearRing(getCoordinates()); - Polygon tri = fact.createPolygon(ring, null); - return tri; - } - - public String toString() { - return getGeometry(new GeometryFactory()).toString(); - } - - /** - * Tests whether this triangle is adjacent to the outside of the subdivision. - * - * @return true if the triangle is adjacent to the subdivision exterior - */ - public boolean isBorder() { - for (int i = 0; i < 3; i++) { - if (getAdjacentTriangleAcrossEdge(i) == null) - return true; - } - return false; - } - - public boolean isBorder(int i) { - return getAdjacentTriangleAcrossEdge(i) == null; - } - - public QuadEdgeTriangle getAdjacentTriangleAcrossEdge(int edgeIndex) { - return (QuadEdgeTriangle) getEdge(edgeIndex).sym().getData(); - } - - public int getAdjacentTriangleEdgeIndex(int i) { - return getAdjacentTriangleAcrossEdge(i).getEdgeIndex(getEdge(i).sym()); - } - - /** - * Gets the triangles which are adjacent (include) to a - * given vertex of this triangle. - * - * @param vertexIndex the vertex to query - * @return a list of the vertex-adjacent triangles - */ - public List getTrianglesAdjacentToVertex(int vertexIndex) { - // Assert: isVertex - List adjTris = new ArrayList(); - - QuadEdge start = getEdge(vertexIndex); - QuadEdge qe = start; - do { - QuadEdgeTriangle adjTri = (QuadEdgeTriangle) qe.getData(); - if (adjTri != null) { - adjTris.add(adjTri); - } - qe = qe.oNext(); - } while (qe != start); - - return adjTris; - - } - - /** - * Gets the neighbours of this triangle. If there is no neighbour triangle, - * the array element is null - * - * @return an array containing the 3 neighbours of this triangle - */ - public QuadEdgeTriangle[] getNeighbours() { - QuadEdgeTriangle[] neigh = new QuadEdgeTriangle[3]; - for (int i = 0; i < 3; i++) { - neigh[i] = (QuadEdgeTriangle) getEdge(i).sym().getData(); - } - return neigh; - } - - private static class QuadEdgeTriangleBuilderVisitor implements TriangleVisitor { - private List triangles = new ArrayList(); - - public QuadEdgeTriangleBuilderVisitor() { - } - - public void visit(QuadEdge[] edges) { - triangles.add(new QuadEdgeTriangle(edges)); - } - - public List getTriangles() { - return triangles; - } - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeUtil.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeUtil.java deleted file mode 100644 index 3dcb2c908f..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeUtil.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -import java.util.ArrayList; -import java.util.List; - -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.io.ParseException; -import com.vividsolutions.jts.io.WKTReader; - -/** - * Utilities for working with {@link QuadEdge}s. - * - * @author mbdavis - * - */ -public class QuadEdgeUtil -{ - /** - * Gets all edges which are incident on the origin of the given edge. - * - * @param start - * the edge to start at - * @return a List of edges which have their origin at the origin of the given - * edge - */ - public static List findEdgesIncidentOnOrigin(QuadEdge start) { - List incEdge = new ArrayList(); - - QuadEdge qe = start; - do { - incEdge.add(qe); - qe = qe.oNext(); - } while (qe != start); - - return incEdge; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TraversalVisitor.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TraversalVisitor.java deleted file mode 100644 index 90fe086781..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TraversalVisitor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -/** - * Interface for classes which process triangles visited during travesals of a - * {@link QuadEdgeSubdivision} - * - * @author Martin Davis - */ -public interface TraversalVisitor { - /** - * Visits a triangle during a traversal of a {@link QuadEdgeSubdivision}. An implementation of - * this method may perform processing on the current triangle. It must also decide whether a - * neighbouring triangle should be added to the queue so its neighbours are visited. Often it - * will perform processing on the neighbour triangle as well, in order to mark it as processed - * (visited) and/or to determine if it should be visited. Note that choosing not to - * visit the neighbouring triangle is the terminating condition for many traversal algorithms. - * In particular, if the neighbour triangle has already been visited, it should not be visited - * again. - * - * @param currTri the current triangle being processed - * @param edgeIndex the index of the edge in the current triangle being traversed - * @param neighbTri a neighbouring triangle next in line to visit - * @return true if the neighbour triangle should be visited - */ - boolean visit(QuadEdgeTriangle currTri, int edgeIndex, QuadEdgeTriangle neighbTri); -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java deleted file mode 100644 index ac82e60ae8..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java +++ /dev/null @@ -1,335 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.triangulate.quadedge; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Triangle; -import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; -import com.vividsolutions.jts.io.WKTWriter; -import com.vividsolutions.jts.math.DD; - -/** - * Algorithms for computing values and predicates - * associated with triangles. - * For some algorithms extended-precision - * implementations are provided, which are more robust - * (i.e. they produce correct answers in more cases). - * Also, some more robust formulations of - * some algorithms are provided, which utilize - * normalization to the origin. - * - * @author Martin Davis - * - */ -public class TrianglePredicate -{ - /** - * Tests if a point is inside the circle defined by - * the triangle with vertices a, b, c (oriented counter-clockwise). - * This test uses simple - * double-precision arithmetic, and thus may not be robust. - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - * @return true if this point is inside the circle defined by the points a, b, c - */ - public static boolean isInCircleNonRobust( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - boolean isInCircle = - (a.x * a.x + a.y * a.y) * triArea(b, c, p) - - (b.x * b.x + b.y * b.y) * triArea(a, c, p) - + (c.x * c.x + c.y * c.y) * triArea(a, b, p) - - (p.x * p.x + p.y * p.y) * triArea(a, b, c) - > 0; - return isInCircle; - } - - /** - * Tests if a point is inside the circle defined by - * the triangle with vertices a, b, c (oriented counter-clockwise). - * This test uses simple - * double-precision arithmetic, and thus is not 100% robust. - * However, by using normalization to the origin - * it provides improved robustness and increased performance. - *

                        - * Based on code by J.R.Shewchuk. - * - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - * @return true if this point is inside the circle defined by the points a, b, c - */ - public static boolean isInCircleNormalized( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - double adx = a.x - p.x; - double ady = a.y - p.y; - double bdx = b.x - p.x; - double bdy = b.y - p.y; - double cdx = c.x - p.x; - double cdy = c.y - p.y; - - double abdet = adx * bdy - bdx * ady; - double bcdet = bdx * cdy - cdx * bdy; - double cadet = cdx * ady - adx * cdy; - double alift = adx * adx + ady * ady; - double blift = bdx * bdx + bdy * bdy; - double clift = cdx * cdx + cdy * cdy; - - double disc = alift * bcdet + blift * cadet + clift * abdet; - return disc > 0; - } - - /** - * Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if the - * triangle is oriented counterclockwise. - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - */ - private static double triArea(Coordinate a, Coordinate b, Coordinate c) { - return (b.x - a.x) * (c.y - a.y) - - (b.y - a.y) * (c.x - a.x); - } - - /** - * Tests if a point is inside the circle defined by - * the triangle with vertices a, b, c (oriented counter-clockwise). - * This method uses more robust computation. - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - * @return true if this point is inside the circle defined by the points a, b, c - */ - public static boolean isInCircleRobust( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) - { - //checkRobustInCircle(a, b, c, p); -// return isInCircleNonRobust(a, b, c, p); - return isInCircleNormalized(a, b, c, p); - } - - /** - * Tests if a point is inside the circle defined by - * the triangle with vertices a, b, c (oriented counter-clockwise). - * The computation uses {@link DD} arithmetic for robustness. - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - * @return true if this point is inside the circle defined by the points a, b, c - */ - public static boolean isInCircleDDSlow( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - DD px = DD.valueOf(p.x); - DD py = DD.valueOf(p.y); - DD ax = DD.valueOf(a.x); - DD ay = DD.valueOf(a.y); - DD bx = DD.valueOf(b.x); - DD by = DD.valueOf(b.y); - DD cx = DD.valueOf(c.x); - DD cy = DD.valueOf(c.y); - - DD aTerm = (ax.multiply(ax).add(ay.multiply(ay))) - .multiply(triAreaDDSlow(bx, by, cx, cy, px, py)); - DD bTerm = (bx.multiply(bx).add(by.multiply(by))) - .multiply(triAreaDDSlow(ax, ay, cx, cy, px, py)); - DD cTerm = (cx.multiply(cx).add(cy.multiply(cy))) - .multiply(triAreaDDSlow(ax, ay, bx, by, px, py)); - DD pTerm = (px.multiply(px).add(py.multiply(py))) - .multiply(triAreaDDSlow(ax, ay, bx, by, cx, cy)); - - DD sum = aTerm.subtract(bTerm).add(cTerm).subtract(pTerm); - boolean isInCircle = sum.doubleValue() > 0; - - return isInCircle; - } - - /** - * Computes twice the area of the oriented triangle (a, b, c), i.e., the area - * is positive if the triangle is oriented counterclockwise. - * The computation uses {@link DD} arithmetic for robustness. - * - * @param ax the x ordinate of a vertex of the triangle - * @param ay the y ordinate of a vertex of the triangle - * @param bx the x ordinate of a vertex of the triangle - * @param by the y ordinate of a vertex of the triangle - * @param cx the x ordinate of a vertex of the triangle - * @param cy the y ordinate of a vertex of the triangle - */ - public static DD triAreaDDSlow(DD ax, DD ay, - DD bx, DD by, DD cx, DD cy) { - return (bx.subtract(ax).multiply(cy.subtract(ay)).subtract(by.subtract(ay) - .multiply(cx.subtract(ax)))); - } - - public static boolean isInCircleDDFast( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - DD aTerm = (DD.sqr(a.x).selfAdd(DD.sqr(a.y))) - .selfMultiply(triAreaDDFast(b, c, p)); - DD bTerm = (DD.sqr(b.x).selfAdd(DD.sqr(b.y))) - .selfMultiply(triAreaDDFast(a, c, p)); - DD cTerm = (DD.sqr(c.x).selfAdd(DD.sqr(c.y))) - .selfMultiply(triAreaDDFast(a, b, p)); - DD pTerm = (DD.sqr(p.x).selfAdd(DD.sqr(p.y))) - .selfMultiply(triAreaDDFast(a, b, c)); - - DD sum = aTerm.selfSubtract(bTerm).selfAdd(cTerm).selfSubtract(pTerm); - boolean isInCircle = sum.doubleValue() > 0; - - return isInCircle; - } - - public static DD triAreaDDFast( - Coordinate a, Coordinate b, Coordinate c) { - - DD t1 = DD.valueOf(b.x).selfSubtract(a.x) - .selfMultiply( - DD.valueOf(c.y).selfSubtract(a.y)); - - DD t2 = DD.valueOf(b.y).selfSubtract(a.y) - .selfMultiply( - DD.valueOf(c.x).selfSubtract(a.x)); - - return t1.selfSubtract(t2); - } - - public static boolean isInCircleDDNormalized( - Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - DD adx = DD.valueOf(a.x).selfSubtract(p.x); - DD ady = DD.valueOf(a.y).selfSubtract(p.y); - DD bdx = DD.valueOf(b.x).selfSubtract(p.x); - DD bdy = DD.valueOf(b.y).selfSubtract(p.y); - DD cdx = DD.valueOf(c.x).selfSubtract(p.x); - DD cdy = DD.valueOf(c.y).selfSubtract(p.y); - - DD abdet = adx.multiply(bdy).selfSubtract(bdx.multiply(ady)); - DD bcdet = bdx.multiply(cdy).selfSubtract(cdx.multiply(bdy)); - DD cadet = cdx.multiply(ady).selfSubtract(adx.multiply(cdy)); - DD alift = adx.multiply(adx).selfAdd(ady.multiply(ady)); - DD blift = bdx.multiply(bdx).selfAdd(bdy.multiply(bdy)); - DD clift = cdx.multiply(cdx).selfAdd(cdy.multiply(cdy)); - - DD sum = alift.selfMultiply(bcdet) - .selfAdd(blift.selfMultiply(cadet)) - .selfAdd(clift.selfMultiply(abdet)); - - boolean isInCircle = sum.doubleValue() > 0; - - return isInCircle; - } - - /** - * Computes the inCircle test using distance from the circumcentre. - * Uses standard double-precision arithmetic. - *

                        - * In general this doesn't - * appear to be any more robust than the standard calculation. However, there - * is at least one case where the test point is far enough from the - * circumcircle that this test gives the correct answer. - *

                        -   * LINESTRING
                        -   * (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258,
                        -   * 1507029.9833 518325.7458, 1507029.9896965567 518325.744909031)
                        -   * 
                        - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - * @return true if this point is inside the circle defined by the points a, b, c - */ - public static boolean isInCircleCC(Coordinate a, Coordinate b, Coordinate c, - Coordinate p) { - Coordinate cc = Triangle.circumcentre(a, b, c); - double ccRadius = a.distance(cc); - double pRadiusDiff = p.distance(cc) - ccRadius; - return pRadiusDiff <= 0; - } - - /** - * Checks if the computed value for isInCircle is correct, using - * double-double precision arithmetic. - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @param p the point to test - */ -private static void checkRobustInCircle(Coordinate a, Coordinate b, Coordinate c, - Coordinate p) -{ - boolean nonRobustInCircle = isInCircleNonRobust(a, b, c, p); - boolean isInCircleDD = TrianglePredicate.isInCircleDDSlow(a, b, c, p); - boolean isInCircleCC = TrianglePredicate.isInCircleCC(a, b, c, p); - - Coordinate circumCentre = Triangle.circumcentre(a, b, c); - System.out.println("p radius diff a = " - + Math.abs(p.distance(circumCentre) - a.distance(circumCentre)) - / a.distance(circumCentre)); - - if (nonRobustInCircle != isInCircleDD || nonRobustInCircle != isInCircleCC) { - System.out.println("inCircle robustness failure (double result = " - + nonRobustInCircle - + ", DD result = " + isInCircleDD - + ", CC result = " + isInCircleCC + ")"); - System.out.println(WKTWriter.toLineString(new CoordinateArraySequence( - new Coordinate[] { a, b, c, p }))); - System.out.println("Circumcentre = " + WKTWriter.toPoint(circumCentre) - + " radius = " + a.distance(circumCentre)); - System.out.println("p radius diff a = " - + Math.abs(p.distance(circumCentre)/a.distance(circumCentre) - 1)); - System.out.println("p radius diff b = " - + Math.abs(p.distance(circumCentre)/b.distance(circumCentre) - 1)); - System.out.println("p radius diff c = " - + Math.abs(p.distance(circumCentre)/c.distance(circumCentre) - 1)); - System.out.println(); - } -} - - -} diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TriangleVisitor.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TriangleVisitor.java deleted file mode 100644 index be3de5de7d..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/TriangleVisitor.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - -/** - * An interface for algorithms which process the triangles in a {@link QuadEdgeSubdivision}. - * - * @author Martin Davis - * @version 1.0 - */ -public interface TriangleVisitor { - /** - * Visits the {@link QuadEdge}s of a triangle. - * - * @param triEdges an array of the 3 quad edges in a triangle (in CCW order) - */ - void visit(QuadEdge[] triEdges); -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/Vertex.java b/src/main/java/com/vividsolutions/jts/triangulate/quadedge/Vertex.java deleted file mode 100644 index ec29542e9e..0000000000 --- a/src/main/java/com/vividsolutions/jts/triangulate/quadedge/Vertex.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ - -package com.vividsolutions.jts.triangulate.quadedge; - - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Triangle; -import com.vividsolutions.jts.geom.impl.CoordinateArraySequence; -import com.vividsolutions.jts.io.WKTWriter; -import com.vividsolutions.jts.algorithm.*; - -/** - * Models a site (node) in a {@link QuadEdgeSubdivision}. - * The sites can be points on a line string representing a - * linear site. - *

                        - * The vertex can be considered as a vector with a norm, length, inner product, cross - * product, etc. Additionally, point relations (e.g., is a point to the left of a line, the circle - * defined by this point and two others, etc.) are also defined in this class. - *

                        - * It is common to want to attach user-defined data to - * the vertices of a subdivision. - * One way to do this is to subclass Vertex - * to carry any desired information. - * - * @author David Skea - * @author Martin Davis - */ -public class Vertex -{ - public static final int LEFT = 0; - public static final int RIGHT = 1; - public static final int BEYOND = 2; - public static final int BEHIND = 3; - public static final int BETWEEN = 4; - public static final int ORIGIN = 5; - public static final int DESTINATION = 6; - - private Coordinate p; - // private int edgeNumber = -1; - - public Vertex(double _x, double _y) { - p = new Coordinate(_x, _y); - } - - public Vertex(double _x, double _y, double _z) { - p = new Coordinate(_x, _y, _z); - } - - public Vertex(Coordinate _p) { - p = new Coordinate(_p); - } - - public double getX() { - return p.x; - } - - public double getY() { - return p.y; - } - - public double getZ() { - return p.z; - } - - public void setZ(double _z) { - p.z = _z; - } - - public Coordinate getCoordinate() { - return p; - } - - public String toString() { - return "POINT (" + p.x + " " + p.y + ")"; - } - - public boolean equals(Vertex _x) { - if (p.x == _x.getX() && p.y == _x.getY()) { - return true; - } else { - return false; - } - } - - public boolean equals(Vertex _x, double tolerance) { - if (p.distance(_x.getCoordinate()) < tolerance) { - return true; - } else { - return false; - } - } - - public int classify(Vertex p0, Vertex p1) { - Vertex p2 = this; - Vertex a = p1.sub(p0); - Vertex b = p2.sub(p0); - double sa = a.crossProduct(b); - if (sa > 0.0) - return LEFT; - if (sa < 0.0) - return RIGHT; - if ((a.getX() * b.getX() < 0.0) || (a.getY() * b.getY() < 0.0)) - return BEHIND; - if (a.magn() < b.magn()) - return BEYOND; - if (p0.equals(p2)) - return ORIGIN; - if (p1.equals(p2)) - return DESTINATION; - return BETWEEN; - } - - /** - * Computes the cross product k = u X v. - * - * @param v a vertex - * @return returns the magnitude of u X v - */ - double crossProduct(Vertex v) { - return (p.x * v.getY() - p.y * v.getX()); - } - - /** - * Computes the inner or dot product - * - * @param v a vertex - * @return returns the dot product u.v - */ - double dot(Vertex v) { - return (p.x * v.getX() + p.y * v.getY()); - } - - /** - * Computes the scalar product c(v) - * - * @param v a vertex - * @return returns the scaled vector - */ - Vertex times(double c) { - return (new Vertex(c * p.x, c * p.y)); - } - - /* Vector addition */ - Vertex sum(Vertex v) { - return (new Vertex(p.x + v.getX(), p.y + v.getY())); - } - - /* and subtraction */ - Vertex sub(Vertex v) { - return (new Vertex(p.x - v.getX(), p.y - v.getY())); - } - - /* magnitude of vector */ - double magn() { - return (Math.sqrt(p.x * p.x + p.y * p.y)); - } - - /* returns k X v (cross product). this is a vector perpendicular to v */ - Vertex cross() { - return (new Vertex(p.y, -p.x)); - } - - /** ************************************************************* */ - /*********************************************************************************************** - * Geometric primitives / - **********************************************************************************************/ - - /** - * Tests if the vertex is inside the circle defined by - * the triangle with vertices a, b, c (oriented counter-clockwise). - * - * @param a a vertex of the triangle - * @param b a vertex of the triangle - * @param c a vertex of the triangle - * @return true if this vertex is in the circumcircle of (a,b,c) - */ - public boolean isInCircle(Vertex a, Vertex b, Vertex c) - { - return TrianglePredicate.isInCircleRobust(a.p, b.p, c.p, this.p); - // non-robust - best to not use - //return TrianglePredicate.isInCircle(a.p, b.p, c.p, this.p); - } - - /** - * Tests whether the triangle formed by this vertex and two - * other vertices is in CCW orientation. - * - * @param b a vertex - * @param c a vertex - * @returns true if the triangle is oriented CCW - */ - public final boolean isCCW(Vertex b, Vertex c) - { - /* - // test code used to check for robustness of triArea - boolean isCCW = (b.p.x - p.x) * (c.p.y - p.y) - - (b.p.y - p.y) * (c.p.x - p.x) > 0; - //boolean isCCW = triArea(this, b, c) > 0; - boolean isCCWRobust = CGAlgorithms.orientationIndex(p, b.p, c.p) == CGAlgorithms.COUNTERCLOCKWISE; - if (isCCWRobust != isCCW) - System.out.println("CCW failure"); - //*/ - - // is equal to the signed area of the triangle - - return (b.p.x - p.x) * (c.p.y - p.y) - - (b.p.y - p.y) * (c.p.x - p.x) > 0; - - // original rolled code - //boolean isCCW = triArea(this, b, c) > 0; - //return isCCW; - - } - - public final boolean rightOf(QuadEdge e) { - return isCCW(e.dest(), e.orig()); - } - - public final boolean leftOf(QuadEdge e) { - return isCCW(e.orig(), e.dest()); - } - - private HCoordinate bisector(Vertex a, Vertex b) { - // returns the perpendicular bisector of the line segment ab - double dx = b.getX() - a.getX(); - double dy = b.getY() - a.getY(); - HCoordinate l1 = new HCoordinate(a.getX() + dx / 2.0, a.getY() + dy / 2.0, 1.0); - HCoordinate l2 = new HCoordinate(a.getX() - dy + dx / 2.0, a.getY() + dx + dy / 2.0, 1.0); - return new HCoordinate(l1, l2); - } - - private double distance(Vertex v1, Vertex v2) { - return Math.sqrt(Math.pow(v2.getX() - v1.getX(), 2.0) - + Math.pow(v2.getY() - v1.getY(), 2.0)); - } - - /** - * Computes the value of the ratio of the circumradius to shortest edge. If smaller than some - * given tolerance B, the associated triangle is considered skinny. For an equal lateral - * triangle this value is 0.57735. The ratio is related to the minimum triangle angle theta by: - * circumRadius/shortestEdge = 1/(2sin(theta)). - * - * @param b second vertex of the triangle - * @param c third vertex of the triangle - * @return ratio of circumradius to shortest edge. - */ - public double circumRadiusRatio(Vertex b, Vertex c) { - Vertex x = this.circleCenter(b, c); - double radius = distance(x, b); - double edgeLength = distance(this, b); - double el = distance(b, c); - if (el < edgeLength) { - edgeLength = el; - } - el = distance(c, this); - if (el < edgeLength) { - edgeLength = el; - } - return radius / edgeLength; - } - - /** - * returns a new vertex that is mid-way between this vertex and another end point. - * - * @param a the other end point. - * @return the point mid-way between this and that. - */ - public Vertex midPoint(Vertex a) { - double xm = (p.x + a.getX()) / 2.0; - double ym = (p.y + a.getY()) / 2.0; - double zm = (p.z + a.getZ()) / 2.0; - return new Vertex(xm, ym, zm); - } - - /** - * Computes the centre of the circumcircle of this vertex and two others. - * - * @param b - * @param c - * @return the Coordinate which is the circumcircle of the 3 points. - */ - public Vertex circleCenter(Vertex b, Vertex c) { - Vertex a = new Vertex(this.getX(), this.getY()); - // compute the perpendicular bisector of cord ab - HCoordinate cab = bisector(a, b); - // compute the perpendicular bisector of cord bc - HCoordinate cbc = bisector(b, c); - // compute the intersection of the bisectors (circle radii) - HCoordinate hcc = new HCoordinate(cab, cbc); - Vertex cc = null; - try { - cc = new Vertex(hcc.getX(), hcc.getY()); - } catch (NotRepresentableException nre) { - System.err.println("a: " + a + " b: " + b + " c: " + c); - System.err.println(nre); - } - return cc; - } - - /** - * For this vertex enclosed in a triangle defined by three vertices v0, v1 and v2, interpolate - * a z value from the surrounding vertices. - */ - public double interpolateZValue(Vertex v0, Vertex v1, Vertex v2) { - double x0 = v0.getX(); - double y0 = v0.getY(); - double a = v1.getX() - x0; - double b = v2.getX() - x0; - double c = v1.getY() - y0; - double d = v2.getY() - y0; - double det = a * d - b * c; - double dx = this.getX() - x0; - double dy = this.getY() - y0; - double t = (d * dx - b * dy) / det; - double u = (-c * dx + a * dy) / det; - double z = v0.getZ() + t * (v1.getZ() - v0.getZ()) + u * (v2.getZ() - v0.getZ()); - return z; - } - - /** - * Interpolates the Z-value (height) of a point enclosed in a triangle - * whose vertices all have Z values. - * The containing triangle must not be degenerate - * (in other words, the three vertices must enclose a - * non-zero area). - * - * @param p the point to interpolate the Z value of - * @param v0 a vertex of a triangle containing the p - * @param v1 a vertex of a triangle containing the p - * @param v2 a vertex of a triangle containing the p - * @return the interpolated Z-value (height) of the point - */ - public static double interpolateZ(Coordinate p, Coordinate v0, Coordinate v1, Coordinate v2) { - double x0 = v0.x; - double y0 = v0.y; - double a = v1.x - x0; - double b = v2.x - x0; - double c = v1.y - y0; - double d = v2.y - y0; - double det = a * d - b * c; - double dx = p.x - x0; - double dy = p.y - y0; - double t = (d * dx - b * dy) / det; - double u = (-c * dx + a * dy) / det; - double z = v0.z + t * (v1.z - v0.z) + u * (v2.z - v0.z); - return z; - } - - /** - * Computes the interpolated Z-value for a point p lying on the segment p0-p1 - * - * @param p - * @param p0 - * @param p1 - * @return the interpolated Z value - */ - public static double interpolateZ(Coordinate p, Coordinate p0, Coordinate p1) { - double segLen = p0.distance(p1); - double ptLen = p.distance(p0); - double dz = p1.z - p0.z; - double pz = p0.z + dz * (ptLen / segLen); - return pz; - } - - - - - - - -} diff --git a/src/main/java/com/vividsolutions/jts/util/Assert.java b/src/main/java/com/vividsolutions/jts/util/Assert.java deleted file mode 100644 index ee1a97e43c..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/Assert.java +++ /dev/null @@ -1,126 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import com.vividsolutions.jts.util.AssertionFailedException; - -/** - * A utility for making programming assertions. - * - *@version 1.7 - */ -public class Assert { - - /** - * Throws an AssertionFailedException if the given assertion is - * not true. - * - *@param assertion a condition that is supposed to be true - *@throws AssertionFailedException if the condition is false - */ - public static void isTrue(boolean assertion) { - isTrue(assertion, null); - } - - /** - * Throws an AssertionFailedException with the given message if - * the given assertion is not true. - * - *@param assertion a condition that is supposed to be true - *@param message a description of the assertion - *@throws AssertionFailedException if the condition is false - */ - public static void isTrue(boolean assertion, String message) { - if (!assertion) { - if (message == null) { - throw new AssertionFailedException(); - } - else { - throw new AssertionFailedException(message); - } - } - } - - /** - * Throws an AssertionFailedException if the given objects are - * not equal, according to the equals method. - * - *@param expectedValue the correct value - *@param actualValue the value being checked - *@throws AssertionFailedException if the two objects are not equal - */ - public static void equals(Object expectedValue, Object actualValue) { - equals(expectedValue, actualValue, null); - } - - /** - * Throws an AssertionFailedException with the given message if - * the given objects are not equal, according to the equals - * method. - * - *@param expectedValue the correct value - *@param actualValue the value being checked - *@param message a description of the assertion - *@throws AssertionFailedException if the two objects are not equal - */ - public static void equals(Object expectedValue, Object actualValue, String message) { - if (!actualValue.equals(expectedValue)) { - throw new AssertionFailedException("Expected " + expectedValue + " but encountered " - + actualValue + (message != null ? ": " + message : "")); - } - } - - /** - * Always throws an AssertionFailedException. - * - *@throws AssertionFailedException thrown always - */ - public static void shouldNeverReachHere() { - shouldNeverReachHere(null); - } - - /** - * Always throws an AssertionFailedException with the given - * message. - * - *@param message a description of the assertion - *@throws AssertionFailedException thrown always - */ - public static void shouldNeverReachHere(String message) { - throw new AssertionFailedException("Should never reach here" - + (message != null ? ": " + message : "")); - } -} - diff --git a/src/main/java/com/vividsolutions/jts/util/AssertionFailedException.java b/src/main/java/com/vividsolutions/jts/util/AssertionFailedException.java deleted file mode 100644 index ddca70cbf4..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/AssertionFailedException.java +++ /dev/null @@ -1,63 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -/** - * Thrown when the application is in an inconsistent state. Indicates a problem - * with the code. - * - *@version 1.7 - */ -public class AssertionFailedException extends RuntimeException { - - /** - * Creates an AssertionFailedException. - */ - public AssertionFailedException() { - super(); - } - - /** - * Creates a AssertionFailedException with the given detail - * message. - * - *@param message a description of the assertion - */ - public AssertionFailedException(String message) { - super(message); - } -} - - diff --git a/src/main/java/com/vividsolutions/jts/util/CollectionUtil.java b/src/main/java/com/vividsolutions/jts/util/CollectionUtil.java deleted file mode 100644 index 82c9d9ce98..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/CollectionUtil.java +++ /dev/null @@ -1,100 +0,0 @@ -/* -* The JTS Topology Suite is a collection of Java classes that -* implement the fundamental operations required to validate a given -* geo-spatial data set to a known topological specification. -* -* Copyright (C) 2001 Vivid Solutions -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* For more information, contact: -* -* Vivid Solutions -* Suite #1A -* 2328 Government Street -* Victoria BC V8T 5G5 -* Canada -* -* (250)385-6040 -* www.vividsolutions.com -*/ - -package com.vividsolutions.jts.util; - -import java.util.*; - -/** - * Utilities for processing {@link Collection}s. - * - * @version 1.7 - */ -public class CollectionUtil -{ - - public interface Function { - Object execute(Object obj); - } - - /** - * Executes a function on each item in a {@link Collection} - * and returns the results in a new {@link List} - * - * @param coll the collection to process - * @param func the Function to execute - * @return a list of the transformed objects - */ - public static List transform(Collection coll, Function func) - { - List result = new ArrayList(); - for (Iterator i = coll.iterator(); i.hasNext(); ) { - result.add(func.execute(i.next())); - } - return result; - } - - /** - * Executes a function on each item in a Collection but does - * not accumulate the result - * - * @param coll the collection to process - * @param func the Function to execute - */ - public static void apply(Collection coll, Function func) - { - for (Iterator i = coll.iterator(); i.hasNext(); ) { - func.execute(i.next()); - } - } - - /** - * Executes a {@link Function} on each item in a Collection - * and collects all the entries for which the result - * of the function is equal to {@link Boolean} true. - * - * @param collection the collection to process - * @param func the Function to execute - * @return a list of objects for which the function was true - */ - public static List select(Collection collection, Function func) { - List result = new ArrayList(); - for (Iterator i = collection.iterator(); i.hasNext();) { - Object item = i.next(); - if (Boolean.TRUE.equals(func.execute(item))) { - result.add(item); - } - } - return result; - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/CoordinateArrayFilter.java b/src/main/java/com/vividsolutions/jts/util/CoordinateArrayFilter.java deleted file mode 100644 index 0f319f0191..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/CoordinateArrayFilter.java +++ /dev/null @@ -1,72 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import com.vividsolutions.jts.geom.*; - -/** - * A {@link CoordinateFilter} that creates an array containing every - * coordinate in a {@link Geometry}. - * - *@version 1.7 - */ -public class CoordinateArrayFilter implements CoordinateFilter { - Coordinate[] pts = null; - int n = 0; - - /** - * Constructs a CoordinateArrayFilter. - * - *@param size the number of points that the CoordinateArrayFilter - * will collect - */ - public CoordinateArrayFilter(int size) { - pts = new Coordinate[size]; - } - - /** - * Returns the gathered Coordinates. - * - *@return the Coordinates collected by this CoordinateArrayFilter - */ - public Coordinate[] getCoordinates() { - return pts; - } - - public void filter(Coordinate coord) { - pts[n++] = coord; - } -} - diff --git a/src/main/java/com/vividsolutions/jts/util/CoordinateCountFilter.java b/src/main/java/com/vividsolutions/jts/util/CoordinateCountFilter.java deleted file mode 100644 index 8859581987..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/CoordinateCountFilter.java +++ /dev/null @@ -1,63 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import com.vividsolutions.jts.geom.*; - -/** - * A {@link CoordinateFilter} that counts the total number of coordinates - * in a Geometry. - * - *@version 1.7 - */ -public class CoordinateCountFilter implements CoordinateFilter { - private int n = 0; - - public CoordinateCountFilter() { } - - /** - * Returns the result of the filtering. - * - *@return the number of points found by this CoordinateCountFilter - */ - public int getCount() { - return n; - } - - public void filter(Coordinate coord) { - n++; - } -} - diff --git a/src/main/java/com/vividsolutions/jts/util/Debug.java b/src/main/java/com/vividsolutions/jts/util/Debug.java deleted file mode 100644 index edff60dad3..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/Debug.java +++ /dev/null @@ -1,342 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -/** - *@version 1.7 - */ -import java.io.*; -import java.util.*; -import java.lang.reflect.*; -import com.vividsolutions.jts.geom.*; - -/** - * Provides routines to simplify and localize debugging output. - * Debugging is controlled via a Java system property value. - * If the system property with the name given in - * DEBUG_PROPERTY_NAME (currently "jts.debug") has the value - * "on" or "true" debugging is enabled. - * Otherwise, debugging is disabled. - * The system property can be set by specifying the following JVM option: - *

                        - * -Djts.debug=on
                        - * 
                        - * - * - * @version 1.7 - */ -public class Debug { - - public static String DEBUG_PROPERTY_NAME = "jts.debug"; - public static String DEBUG_PROPERTY_VALUE_ON = "on"; - public static String DEBUG_PROPERTY_VALUE_TRUE = "true"; - - private static boolean debugOn = false; - - static { - String debugValue = System.getProperty(DEBUG_PROPERTY_NAME); - if (debugValue != null) { - if (debugValue.equalsIgnoreCase(DEBUG_PROPERTY_VALUE_ON) - || debugValue.equalsIgnoreCase(DEBUG_PROPERTY_VALUE_TRUE) ) - debugOn = true; - } - } - - private static Stopwatch stopwatch = new Stopwatch(); - private static long lastTimePrinted; - - /** - * Prints the status of debugging to System.out - * - * @param args the cmd-line arguments (no arguments are required) - */ - public static void main(String[] args) - { - System.out.println("JTS Debugging is " + - (debugOn ? "ON" : "OFF") ); - } - - private static final Debug debug = new Debug(); - private static final GeometryFactory fact = new GeometryFactory(); - private static final String DEBUG_LINE_TAG = "D! "; - - private PrintStream out; - private Class[] printArgs; - private Object watchObj = null; - private Object[] args = new Object[1]; - - public static boolean isDebugging() { return debugOn; } - - public static LineString toLine(Coordinate p0, Coordinate p1) { - return fact.createLineString(new Coordinate[] { p0, p1 }); - } - - public static LineString toLine(Coordinate p0, Coordinate p1, Coordinate p2) { - return fact.createLineString(new Coordinate[] { p0, p1, p2}); - } - - public static LineString toLine(Coordinate p0, Coordinate p1, Coordinate p2, Coordinate p3) { - return fact.createLineString(new Coordinate[] { p0, p1, p2, p3}); - } - - public static void print(String str) { - if (!debugOn) { - return; - } - debug.instancePrint(str); - } -/* - public static void println(String str) { - if (! debugOn) return; - debug.instancePrint(str); - debug.println(); - } -*/ - public static void print(Object obj) { - if (! debugOn) return; - debug.instancePrint(obj); - } - - public static void print(boolean isTrue, Object obj) { - if (! debugOn) return; - if (! isTrue) return; - debug.instancePrint(obj); - } - - public static void println(Object obj) { - if (!debugOn) { - return; - } - debug.instancePrint(obj); - debug.println(); - } - - public static void resetTime() - { - stopwatch.reset(); - lastTimePrinted = stopwatch.getTime(); - } - - public static void printTime(String tag) - { - if (!debugOn) { - return; - } - long time = stopwatch.getTime(); - long elapsedTime = time - lastTimePrinted; - debug.instancePrint( - formatField(Stopwatch.getTimeString(time), 10) - + " (" + formatField(Stopwatch.getTimeString(elapsedTime), 10) + " ) " - + tag); - debug.println(); - lastTimePrinted = time; - } - - private static String formatField(String s, int fieldLen) - { - int nPad = fieldLen - s.length(); - if (nPad <= 0) return s; - String padStr = spaces(nPad) + s; - return padStr.substring(padStr.length() - fieldLen); - } - - private static String spaces(int n) - { - char[] ch = new char[n]; - for (int i = 0; i < n; i++) { - ch[i] = ' '; - } - return new String(ch); - } - - public static boolean equals(Coordinate c1, Coordinate c2, double tolerance) - { - return c1.distance(c2) <= tolerance; - } - /** - * Adds an object to be watched. - * A watched object can be printed out at any time. - * - * Currently only supports one watched object at a time. - * @param obj - */ - public static void addWatch(Object obj) { - debug.instanceAddWatch(obj); - } - - public static void printWatch() { - debug.instancePrintWatch(); - } - - public static void printIfWatch(Object obj) { - debug.instancePrintIfWatch(obj); - } - - public static void breakIf(boolean cond) - { - if (cond) doBreak(); - } - - public static void breakIfEqual(Object o1, Object o2) - { - if (o1.equals(o2)) doBreak(); - } - - public static void breakIfEqual(Coordinate p0, Coordinate p1, double tolerance) - { - if (p0.distance(p1) <= tolerance) doBreak(); - } - - private static void doBreak() - { - // Put breakpoint on following statement to break here - return; - } - - public static boolean hasSegment(Geometry geom, Coordinate p0, Coordinate p1) - { - SegmentFindingFilter filter = new SegmentFindingFilter(p0, p1); - geom.apply(filter); - return filter.hasSegment(); - } - - private static class SegmentFindingFilter - implements CoordinateSequenceFilter - { - private Coordinate p0, p1; - private boolean hasSegment = false; - - public SegmentFindingFilter(Coordinate p0, Coordinate p1) - { - this.p0 = p0; - this.p1 = p1; - } - - public boolean hasSegment() { return hasSegment; } - - public void filter(CoordinateSequence seq, int i) - { - if (i == 0) return; - hasSegment = p0.equals2D(seq.getCoordinate(i-1)) - && p1.equals2D(seq.getCoordinate(i)); - } - - public boolean isDone() - { - return hasSegment; - } - - public boolean isGeometryChanged() - { - return false; - } - } - - private Debug() { - out = System.out; - printArgs = new Class[1]; - try { - printArgs[0] = Class.forName("java.io.PrintStream"); - } - catch (Exception ex) { - // ignore this exception - it will fail later anyway - } - } - - public void instancePrintWatch() { - if (watchObj == null) return; - instancePrint(watchObj); - } - - public void instancePrintIfWatch(Object obj) { - if (obj != watchObj) return; - if (watchObj == null) return; - instancePrint(watchObj); - } - - public void instancePrint(Object obj) - { - if (obj instanceof Collection) { - instancePrint(((Collection) obj).iterator()); - } - else if (obj instanceof Iterator) { - instancePrint((Iterator) obj); - } - else { - instancePrintObject(obj); - } - } - - public void instancePrint(Iterator it) - { - for (; it.hasNext(); ) { - Object obj = it.next(); - instancePrintObject(obj); - } - } - public void instancePrintObject(Object obj) { - //if (true) throw new RuntimeException("DEBUG TRAP!"); - Method printMethod = null; - try { - Class cls = obj.getClass(); - try { - printMethod = cls.getMethod("print", printArgs); - args[0] = out; - out.print(DEBUG_LINE_TAG); - printMethod.invoke(obj, args); - } - catch (NoSuchMethodException ex) { - instancePrint(obj.toString()); - } - } - catch (Exception ex) { - ex.printStackTrace(out); - } - } - - public void println() { - out.println(); - } - - private void instanceAddWatch(Object obj) { - watchObj = obj; - } - - private void instancePrint(String str) { - out.print(DEBUG_LINE_TAG); - out.print(str); - } - -} diff --git a/src/main/java/com/vividsolutions/jts/util/GeometricShapeFactory.java b/src/main/java/com/vividsolutions/jts/util/GeometricShapeFactory.java deleted file mode 100644 index 89c28adda1..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/GeometricShapeFactory.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import com.vividsolutions.jts.geom.*; -import com.vividsolutions.jts.geom.util.AffineTransformation; - -/** - * Computes various kinds of common geometric shapes. - * Provides various ways of specifying the location and extent - * and rotations of the generated shapes, - * as well as number of line segments used to form them. - *

                        - * Example of usage: - *

                        - *  GeometricShapeFactory gsf = new GeometricShapeFactory();
                        - *  gsf.setSize(100);
                        - *  gsf.setNumPoints(100);
                        - *  gsf.setBase(new Coordinate(100, 100));
                        - *  gsf.setRotation(0.5);
                        - *  Polygon rect = gsf.createRectangle();
                        - * 
                        - * - * @version 1.7 - */ -public class GeometricShapeFactory -{ - protected GeometryFactory geomFact; - protected PrecisionModel precModel = null; - protected Dimensions dim = new Dimensions(); - protected int nPts = 100; - - /** - * Default is no rotation. - */ - protected double rotationAngle = 0.0; - - /** - * Create a shape factory which will create shapes using the default - * {@link GeometryFactory}. - */ - public GeometricShapeFactory() - { - this(new GeometryFactory()); - } - - /** - * Create a shape factory which will create shapes using the given - * {@link GeometryFactory}. - * - * @param geomFact the factory to use - */ - public GeometricShapeFactory(GeometryFactory geomFact) - { - this.geomFact = geomFact; - precModel = geomFact.getPrecisionModel(); - } - - public void setEnvelope(Envelope env) - { - dim.setEnvelope(env); - } - - /** - * Sets the location of the shape by specifying the base coordinate - * (which in most cases is the - * lower left point of the envelope containing the shape). - * - * @param base the base coordinate of the shape - */ - public void setBase(Coordinate base) { dim.setBase(base); } - /** - * Sets the location of the shape by specifying the centre of - * the shape's bounding box - * - * @param centre the centre coordinate of the shape - */ - public void setCentre(Coordinate centre) { dim.setCentre(centre); } - - /** - * Sets the total number of points in the created {@link Geometry}. - * The created geometry will have no more than this number of points, - * unless more are needed to create a valid geometry. - */ - public void setNumPoints(int nPts) { this.nPts = nPts; } - - /** - * Sets the size of the extent of the shape in both x and y directions. - * - * @param size the size of the shape's extent - */ - public void setSize(double size) { dim.setSize(size); } - - /** - * Sets the width of the shape. - * - * @param width the width of the shape - */ - public void setWidth(double width) { dim.setWidth(width); } - - /** - * Sets the height of the shape. - * - * @param height the height of the shape - */ - public void setHeight(double height) { dim.setHeight(height); } - - /** - * Sets the rotation angle to use for the shape. - * The rotation is applied relative to the centre of the shape. - * - * @param radians the rotation angle in radians. - */ - public void setRotation(double radians) - { - rotationAngle = radians; - } - - protected Geometry rotate(Geometry geom) - { - if (rotationAngle != 0.0) { - AffineTransformation trans = AffineTransformation.rotationInstance(rotationAngle, - dim.getCentre().x, dim.getCentre().y); - geom.apply(trans); - } - return geom; - } - - /** - * Creates a rectangular {@link Polygon}. - * - * @return a rectangular Polygon - * - */ - public Polygon createRectangle() - { - int i; - int ipt = 0; - int nSide = nPts / 4; - if (nSide < 1) nSide = 1; - double XsegLen = dim.getEnvelope().getWidth() / nSide; - double YsegLen = dim.getEnvelope().getHeight() / nSide; - - Coordinate[] pts = new Coordinate[4 * nSide + 1]; - Envelope env = dim.getEnvelope(); - - //double maxx = env.getMinX() + nSide * XsegLen; - //double maxy = env.getMinY() + nSide * XsegLen; - - for (i = 0; i < nSide; i++) { - double x = env.getMinX() + i * XsegLen; - double y = env.getMinY(); - pts[ipt++] = coord(x, y); - } - for (i = 0; i < nSide; i++) { - double x = env.getMaxX(); - double y = env.getMinY() + i * YsegLen; - pts[ipt++] = coord(x, y); - } - for (i = 0; i < nSide; i++) { - double x = env.getMaxX() - i * XsegLen; - double y = env.getMaxY(); - pts[ipt++] = coord(x, y); - } - for (i = 0; i < nSide; i++) { - double x = env.getMinX(); - double y = env.getMaxY() - i * YsegLen; - pts[ipt++] = coord(x, y); - } - pts[ipt++] = new Coordinate(pts[0]); - - LinearRing ring = geomFact.createLinearRing(pts); - Polygon poly = geomFact.createPolygon(ring, null); - return (Polygon) rotate(poly); - } - -//* @deprecated use {@link createEllipse} instead - /** - * Creates a circular or elliptical {@link Polygon}. - * - * @return a circle or ellipse - */ - public Polygon createCircle() - { - return createEllipse(); - } - - /** - * Creates an elliptical {@link Polygon}. - * If the supplied envelope is square the - * result will be a circle. - * - * @return an ellipse or circle - */ - public Polygon createEllipse() - { - - Envelope env = dim.getEnvelope(); - double xRadius = env.getWidth() / 2.0; - double yRadius = env.getHeight() / 2.0; - - double centreX = env.getMinX() + xRadius; - double centreY = env.getMinY() + yRadius; - - Coordinate[] pts = new Coordinate[nPts + 1]; - int iPt = 0; - for (int i = 0; i < nPts; i++) { - double ang = i * (2 * Math.PI / nPts); - double x = xRadius * Math.cos(ang) + centreX; - double y = yRadius * Math.sin(ang) + centreY; - pts[iPt++] = coord(x, y); - } - pts[iPt] = new Coordinate(pts[0]); - - LinearRing ring = geomFact.createLinearRing(pts); - Polygon poly = geomFact.createPolygon(ring, null); - return (Polygon) rotate(poly); - } - /** - * Creates a squircular {@link Polygon}. - * - * @return a squircle - */ - public Polygon createSquircle() - /** - * Creates a squircular {@link Polygon}. - * - * @return a squircle - */ - { - return createSupercircle(4); - } - - /** - * Creates a supercircular {@link Polygon} - * of a given positive power. - * - * @return a supercircle - */ - public Polygon createSupercircle(double power) - { - double recipPow = 1.0 / power; - - double radius = dim.getMinSize() / 2; - Coordinate centre = dim.getCentre(); - - double r4 = Math.pow(radius, power); - double y0 = radius; - - double xyInt = Math.pow(r4 / 2, recipPow); - - int nSegsInOct = nPts / 8; - int totPts = nSegsInOct * 8 + 1; - Coordinate[] pts = new Coordinate[totPts]; - double xInc = xyInt / nSegsInOct; - - for (int i = 0; i <= nSegsInOct; i++) { - double x = 0.0; - double y = y0; - if (i != 0) { - x = xInc * i; - double x4 = Math.pow(x, power); - y = Math.pow(r4 - x4, recipPow); - } - pts[i] = coordTrans(x, y, centre); - pts[2 * nSegsInOct - i] = coordTrans(y, x, centre); - - pts[2 * nSegsInOct + i] = coordTrans(y, -x, centre); - pts[4 * nSegsInOct - i] = coordTrans(x, -y, centre); - - pts[4 * nSegsInOct + i] = coordTrans(-x, -y, centre); - pts[6 * nSegsInOct - i] = coordTrans(-y, -x, centre); - - pts[6 * nSegsInOct + i] = coordTrans(-y, x, centre); - pts[8 * nSegsInOct - i] = coordTrans(-x, y, centre); - } - pts[pts.length-1] = new Coordinate(pts[0]); - - LinearRing ring = geomFact.createLinearRing(pts); - Polygon poly = geomFact.createPolygon(ring, null); - return (Polygon) rotate(poly); - } - - /** - * Creates an elliptical arc, as a {@link LineString}. - * The arc is always created in a counter-clockwise direction. - * This can easily be reversed if required by using - * {#link LineString.reverse()} - * - * @param startAng start angle in radians - * @param angExtent size of angle in radians - * @return an elliptical arc - */ - public LineString createArc( - double startAng, - double angExtent) - { - Envelope env = dim.getEnvelope(); - double xRadius = env.getWidth() / 2.0; - double yRadius = env.getHeight() / 2.0; - - double centreX = env.getMinX() + xRadius; - double centreY = env.getMinY() + yRadius; - - double angSize = angExtent; - if (angSize <= 0.0 || angSize > 2 * Math.PI) - angSize = 2 * Math.PI; - double angInc = angSize / (nPts - 1); - - Coordinate[] pts = new Coordinate[nPts]; - int iPt = 0; - for (int i = 0; i < nPts; i++) { - double ang = startAng + i * angInc; - double x = xRadius * Math.cos(ang) + centreX; - double y = yRadius * Math.sin(ang) + centreY; - pts[iPt++] = coord(x, y); - } - LineString line = geomFact.createLineString(pts); - return (LineString) rotate(line); - } - - /** - * Creates an elliptical arc polygon. - * The polygon is formed from the specified arc of an ellipse - * and the two radii connecting the endpoints to the centre of the ellipse. - * - * @param startAng start angle in radians - * @param angExtent size of angle in radians - * @return an elliptical arc polygon - */ - public Polygon createArcPolygon(double startAng, double angExtent) { - Envelope env = dim.getEnvelope(); - double xRadius = env.getWidth() / 2.0; - double yRadius = env.getHeight() / 2.0; - - double centreX = env.getMinX() + xRadius; - double centreY = env.getMinY() + yRadius; - - double angSize = angExtent; - if (angSize <= 0.0 || angSize > 2 * Math.PI) - angSize = 2 * Math.PI; - double angInc = angSize / (nPts - 1); - // double check = angInc * nPts; - // double checkEndAng = startAng + check; - - Coordinate[] pts = new Coordinate[nPts + 2]; - - int iPt = 0; - pts[iPt++] = coord(centreX, centreY); - for (int i = 0; i < nPts; i++) { - double ang = startAng + angInc * i; - - double x = xRadius * Math.cos(ang) + centreX; - double y = yRadius * Math.sin(ang) + centreY; - pts[iPt++] = coord(x, y); - } - pts[iPt++] = coord(centreX, centreY); - LinearRing ring = geomFact.createLinearRing(pts); - Polygon poly = geomFact.createPolygon(ring, null); - return (Polygon) rotate(poly); - } - - protected Coordinate coord(double x, double y) - { - Coordinate pt = new Coordinate(x, y); - precModel.makePrecise(pt); - return pt; - } - - protected Coordinate coordTrans(double x, double y, Coordinate trans) - { - return coord(x + trans.x, y + trans.y); - } - - protected class Dimensions - { - public Coordinate base; - public Coordinate centre; - public double width; - public double height; - - public void setBase(Coordinate base) { this.base = base; } - public Coordinate getBase() { return base; } - - public void setCentre(Coordinate centre) { this.centre = centre; } - public Coordinate getCentre() - { - if (centre == null) { - centre = new Coordinate(base.x + width/2, base.y + height/2); - } - return centre; - } - - public void setSize(double size) - { - height = size; - width = size; - } - - public double getMinSize() - { - return Math.min(width, height); - } - public void setWidth(double width) { this.width = width; } - public double getWidth() { return width; } - public double getHeight() { return height; } - - public void setHeight(double height) { this.height = height; } - - public void setEnvelope(Envelope env) - { - this.width = env.getWidth(); - this.height = env.getHeight(); - this.base = new Coordinate(env.getMinX(), env.getMinY()); - this.centre = new Coordinate(env.centre()); - } - - public Envelope getEnvelope() { - if (base != null) { - return new Envelope(base.x, base.x + width, base.y, base.y + height); - } - if (centre != null) { - return new Envelope(centre.x - width/2, centre.x + width/2, - centre.y - height/2, centre.y + height/2); - } - return new Envelope(0, width, 0, height); - } - - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/Memory.java b/src/main/java/com/vividsolutions/jts/util/Memory.java deleted file mode 100644 index 552497bced..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/Memory.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -/** - * Utility functions to report JVM memory usage. - * - * @author mbdavis - * - */ -public class Memory -{ - public static long used() - { - Runtime runtime = Runtime.getRuntime (); - return runtime.totalMemory() - runtime.freeMemory(); - } - - public static String usedString() - { - return format(used()); - } - - public static long free() - { - Runtime runtime = Runtime.getRuntime (); - return runtime.freeMemory(); - } - - public static String freeString() - { - return format(free()); - } - - public static long total() - { - Runtime runtime = Runtime.getRuntime (); - return runtime.totalMemory(); - } - - public static String totalString() - { - return format(total()); - } - - public static String usedTotalString() - { - return "Used: " + usedString() - + " Total: " + totalString(); - } - - public static String allString() - { - return "Used: " + usedString() - + " Free: " + freeString() - + " Total: " + totalString(); - } - - public static final double KB = 1024; - public static final double MB = 1048576; - public static final double GB = 1073741824; - - public static String format(long mem) - { - if (mem < 2 * KB) - return mem + " bytes"; - if (mem < 2 * MB) - return round(mem / KB) + " KB"; - if (mem < 2 * GB) - return round(mem / MB) + " MB"; - return round(mem / GB) + " GB"; - } - - public static double round(double d) - { - return Math.ceil(d * 100) / 100; - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/NumberUtil.java b/src/main/java/com/vividsolutions/jts/util/NumberUtil.java deleted file mode 100644 index ce958606d9..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/NumberUtil.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.vividsolutions.jts.util; - -public class NumberUtil -{ - - public static boolean equalsWithTolerance(double x1, double x2, double tolerance) - { - return Math.abs(x1 - x2) <= tolerance; - } - -} diff --git a/src/main/java/com/vividsolutions/jts/util/ObjectCounter.java b/src/main/java/com/vividsolutions/jts/util/ObjectCounter.java deleted file mode 100644 index 29ec885b48..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/ObjectCounter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import java.util.*; - -/** - * Counts occurences of objects. - * - * @author Martin Davis - * - */ -public class ObjectCounter -{ - - private Map counts = new HashMap(); - - public ObjectCounter() { - } - - public void add(Object o) - { - Counter counter = (Counter) counts.get(o); - if (counter == null) - counts.put(o, new Counter(1)); - else - counter.increment(); - } - - // TODO: add remove(Object o) - - public int count(Object o) - { - Counter counter = (Counter) counts.get(o); - if (counter == null) - return 0; - else - return counter.count(); - - } - private static class Counter - { - int count = 0; - - public Counter() - { - - } - - public Counter(int count) - { - this.count = count; - } - - public int count() - { - return count; - } - - public void increment() - { - count++; - } - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/PriorityQueue.java b/src/main/java/com/vividsolutions/jts/util/PriorityQueue.java deleted file mode 100644 index 98e9153ffd..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/PriorityQueue.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import java.util.*; - -/** - * A priority queue over a set of {@link Comparable} objects. - * - * @author Martin Davis - * - */ -public class PriorityQueue -{ - private int size; // Number of elements in queue - private ArrayList items; // The queue binary heap array - - /** - * Creates a new empty priority queue - */ - public PriorityQueue() { - size = 0; - items = new ArrayList(); - // create space for sentinel - items.add(null); - } - - /** - * Insert into the priority queue. - * Duplicates are allowed. - * @param x the item to insert. - */ - public void add(Comparable x) - { - // increase the size of the items heap to create a hole for the new item - items.add(null); - - // Insert item at end of heap and then re-establish ordering - size += 1; - int hole = size; - // set the item as a sentinel at the base of the heap - items.set(0, x); - - // move the item up from the hole position to its correct place - for (; x.compareTo(items.get(hole / 2)) < 0; hole /= 2) { - items.set(hole, items.get(hole / 2)); - } - // insert the new item in the correct place - items.set(hole, x); - } - - /** - * Establish heap from an arbitrary arrangement of items. - */ - /* - private void buildHeap( ) { - for( int i = currentSize / 2; i > 0; i-- ) - reorder( i ); - } - */ - - /** - * Test if the priority queue is logically empty. - * @return true if empty, false otherwise. - */ - public boolean isEmpty() { - return size == 0; - } - - /** - * Returns size. - * @return current size. - */ - public int size() { - return size; - } - - /** - * Make the priority queue logically empty. - */ - public void clear() { - size = 0; - items.clear(); - } - - /** - * Remove the smallest item from the priority queue. - * @return the smallest item, or null if empty - */ - public Object poll() - { - if (isEmpty()) - return null; - Object minItem = items.get(1); - items.set(1, items.get(size)); - size -= 1; - reorder(1); - - return minItem; - } - - - - /** - * Internal method to percolate down in the heap. - * - * @param hole the index at which the percolate begins. - */ - private void reorder(int hole) - { - int child; - Object tmp = items.get(hole); - - for (; hole * 2 <= size; hole = child) { - child = hole * 2; - if (child != size - && ((Comparable) items.get(child + 1)).compareTo(items.get(child)) < 0) - child++; - if (((Comparable) items.get(child)).compareTo(tmp) < 0) - items.set(hole, items.get(child)); - else - break; - } - items.set(hole, tmp); - } -} \ No newline at end of file diff --git a/src/main/java/com/vividsolutions/jts/util/Stopwatch.java b/src/main/java/com/vividsolutions/jts/util/Stopwatch.java deleted file mode 100644 index 25f1a55936..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/Stopwatch.java +++ /dev/null @@ -1,108 +0,0 @@ - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -/** - * Implements a timer function which can compute - * elapsed time as well as split times. - * - * @version 1.7 - */ -public class Stopwatch { - - private long startTimestamp; - private long totalTime = 0; - private boolean isRunning = false; - - public Stopwatch() - { - start(); - } - - public void start() - { - if (isRunning) return; - startTimestamp = System.currentTimeMillis(); - isRunning = true; - } - - public long stop() - { - if (isRunning) { - updateTotalTime(); - isRunning = false; - } - return totalTime; - } - - public void reset() - { - totalTime = 0; - startTimestamp = System.currentTimeMillis(); - } - - public long split() - { - if (isRunning) - updateTotalTime(); - return totalTime; - } - - private void updateTotalTime() - { - long endTimestamp = System.currentTimeMillis(); - long elapsedTime = endTimestamp - startTimestamp; - startTimestamp = endTimestamp; - totalTime += elapsedTime; - } - - public long getTime() - { - updateTotalTime(); - return totalTime; - } - - public String getTimeString() - { - long totalTime = getTime(); - return getTimeString(totalTime); - } - - public static String getTimeString(long timeMillis) { - String totalTimeStr = timeMillis < 10000 - ? timeMillis + " ms" - : (double) timeMillis / 1000.0 + " s"; - return totalTimeStr; - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/StringUtil.java b/src/main/java/com/vividsolutions/jts/util/StringUtil.java deleted file mode 100644 index 25b75ae63a..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/StringUtil.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.vividsolutions.jts.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.LineNumberReader; -import java.io.PrintStream; -import java.io.StringReader; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; - -/** - * Utility methods for working with {@link String}s. - * - * @author Martin Davis - * - */ -public class StringUtil -{ - /** - * Mimics the the Java SE {@link String#split(String)} method. - * - * @param s the string to split. - * @param separator the separator to use. - * @return the array of split strings. - */ - public static String[] split(String s, String separator) - { - int separatorlen = separator.length(); - ArrayList tokenList = new ArrayList(); - String tmpString = "" + s; - int pos = tmpString.indexOf(separator); - while (pos >= 0) { - String token = tmpString.substring(0, pos); - tokenList.add(token); - tmpString = tmpString.substring(pos + separatorlen); - pos = tmpString.indexOf(separator); - } - if (tmpString.length() > 0) - tokenList.add(tmpString); - String[] res = new String[tokenList.size()]; - for (int i = 0; i < res.length; i++) { - res[i] = (String) tokenList.get(i); - } - return res; - } - - public final static String NEWLINE = System.getProperty("line.separator"); - - /** - * Returns an throwable's stack trace - */ - public static String getStackTrace(Throwable t) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(os); - t.printStackTrace(ps); - return os.toString(); - } - - public static String getStackTrace(Throwable t, int depth) { - String stackTrace = ""; - StringReader stringReader = new StringReader(getStackTrace(t)); - LineNumberReader lineNumberReader = new LineNumberReader(stringReader); - for (int i = 0; i < depth; i++) { - try { - stackTrace += lineNumberReader.readLine() + NEWLINE; - } catch (IOException e) { - Assert.shouldNeverReachHere(); - } - } - return stackTrace; - } - - private static NumberFormat SIMPLE_ORDINATE_FORMAT = new DecimalFormat("0.#"); - - public static String toString(double d) - { - return SIMPLE_ORDINATE_FORMAT.format(d); - } - - public static String spaces(int n) - { - return chars(' ', n); - } - - public static String chars(char c, int n) - { - char[] ch = new char[n]; - for (int i = 0; i < n; i++) { - ch[i] = c; - } - return new String(ch); - } -} diff --git a/src/main/java/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java b/src/main/java/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java deleted file mode 100644 index 82e2e96fef..0000000000 --- a/src/main/java/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java +++ /dev/null @@ -1,89 +0,0 @@ - - -/* - * The JTS Topology Suite is a collection of Java classes that - * implement the fundamental operations required to validate a given - * geo-spatial data set to a known topological specification. - * - * Copyright (C) 2001 Vivid Solutions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For more information, contact: - * - * Vivid Solutions - * Suite #1A - * 2328 Government Street - * Victoria BC V8T 5G5 - * Canada - * - * (250)385-6040 - * www.vividsolutions.com - */ -package com.vividsolutions.jts.util; - -import java.util.ArrayList; -import java.util.TreeSet; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateFilter; - -/** - * A {@link CoordinateFilter} that builds a set of Coordinates. - * The set of coordinates contains no duplicate points. - * It preserves the order of the input points. - * - *@version 1.7 - */ -public class UniqueCoordinateArrayFilter implements CoordinateFilter -{ - /** - * Convenience method which allows running the filter over an array of {@link Coordinate}s. - * - * @param coords an array of coordinates - * @return an array of the unique coordinates - */ - public static Coordinate[] filterCoordinates(Coordinate[] coords) - { - UniqueCoordinateArrayFilter filter = new UniqueCoordinateArrayFilter(); - for (int i = 0; i < coords.length; i++) { - filter.filter(coords[i]); - } - return filter.getCoordinates(); - } - - TreeSet treeSet = new TreeSet(); - ArrayList list = new ArrayList(); - - public UniqueCoordinateArrayFilter() { } - - /** - * Returns the gathered Coordinates. - * - *@return the Coordinates collected by this CoordinateArrayFilter - */ - public Coordinate[] getCoordinates() { - Coordinate[] coordinates = new Coordinate[list.size()]; - return (Coordinate[]) list.toArray(coordinates); - } - - public void filter(Coordinate coord) { - if (!treeSet.contains(coord)) { - list.add(coord); - treeSet.add(coord); - } - } -} - diff --git a/src/main/java/org/datasyslab/geospark/formatMapper/PointFormatMapper.java b/src/main/java/org/datasyslab/geospark/formatMapper/PointFormatMapper.java index 4cc5dc139a..d5de94c4a2 100644 --- a/src/main/java/org/datasyslab/geospark/formatMapper/PointFormatMapper.java +++ b/src/main/java/org/datasyslab/geospark/formatMapper/PointFormatMapper.java @@ -45,29 +45,29 @@ public Point call(String line) throws Exception { coordinate= new Coordinate(Double.parseDouble(lineSplitList.get(0 + this.offset)), Double.parseDouble(lineSplitList.get(1 + this.offset))); point = fact.createPoint(coordinate); + point.setUserData(line); break; case "tsv": lineSplitList = Arrays.asList(line.split("\t")); coordinate = new Coordinate(Double.parseDouble(lineSplitList.get(0 + this.offset)), Double.parseDouble(lineSplitList.get(1 + this.offset))); point = fact.createPoint(coordinate); + point.setUserData(line); break; case "geojson": GeoJSONReader reader = new GeoJSONReader(); point = (Point)reader.read(line); + point.setUserData(line); break; case "wkt": lineSplitList = Arrays.asList(line.split("\t")); WKTReader wktreader = new WKTReader(); - try { - Envelope envelope=wktreader.read(lineSplitList.get(offset)).getEnvelopeInternal(); - coordinate = new Coordinate (envelope.getMinX(),envelope.getMinY()); - point = fact.createPoint(coordinate); - } catch (NullPointerException e) { - coordinate = new Coordinate (85.01,34.01); - point = fact.createPoint(coordinate); - //e.printStackTrace(); - } + Envelope envelope=wktreader.read(lineSplitList.get(offset)).getEnvelopeInternal(); + coordinate = new Coordinate (envelope.getMinX(),envelope.getMinY()); + point = fact.createPoint(coordinate); + coordinate = new Coordinate (85.01,34.01); + point = fact.createPoint(coordinate); + point.setUserData(line); break; default: throw new Exception("Input type not recognized, "); diff --git a/src/main/java/org/datasyslab/geospark/formatMapper/PolygonFormatMapper.java b/src/main/java/org/datasyslab/geospark/formatMapper/PolygonFormatMapper.java index acec97f44a..a664a7e804 100644 --- a/src/main/java/org/datasyslab/geospark/formatMapper/PolygonFormatMapper.java +++ b/src/main/java/org/datasyslab/geospark/formatMapper/PolygonFormatMapper.java @@ -51,6 +51,7 @@ public Polygon call(String line) throws Exception { } linear = fact.createLinearRing(coordinatesList.toArray(new Coordinate[coordinatesList.size()])); polygon = new Polygon(linear, null, fact); + polygon.setUserData(line); break; case "tsv": lineSplitList = Arrays.asList(line.split("\t")); @@ -62,19 +63,18 @@ public Polygon call(String line) throws Exception { coordinates = coordinatesList.toArray(coordinates); linear = fact.createLinearRing(coordinates); polygon = new Polygon(linear, null, fact); + polygon.setUserData(line); break; case "geojson": GeoJSONReader reader = new GeoJSONReader(); polygon = (Polygon) reader.read(line); + polygon.setUserData(line); break; case "wkt": lineSplitList=Arrays.asList(line.split("\t")); WKTReader wtkreader = new WKTReader(); - try { - polygon = (Polygon) wtkreader.read(lineSplitList.get(offset)); - } catch (ParseException e) { - e.printStackTrace(); - } + polygon = (Polygon) wtkreader.read(lineSplitList.get(offset)); + polygon.setUserData(line); break; default: throw new Exception("Input type not recognized, "); diff --git a/src/main/java/org/datasyslab/geospark/formatMapper/RectangleFormatMapper.java b/src/main/java/org/datasyslab/geospark/formatMapper/RectangleFormatMapper.java index 13bb0e2927..7c3003d5ea 100644 --- a/src/main/java/org/datasyslab/geospark/formatMapper/RectangleFormatMapper.java +++ b/src/main/java/org/datasyslab/geospark/formatMapper/RectangleFormatMapper.java @@ -49,6 +49,7 @@ public Envelope call(String line) throws Exception { y1 = Double.parseDouble(lineSplitList.get(offset + 1)); y2 = Double.parseDouble(lineSplitList.get(offset + 3)); rectangle = new Envelope(x1, x2, y1, y2); + rectangle.setUserData(line); break; case "tsv": lineSplitList = Arrays.asList(line.split("\t")); @@ -57,21 +58,19 @@ public Envelope call(String line) throws Exception { y1 = Double.parseDouble(lineSplitList.get(offset + 1)); y2 = Double.parseDouble(lineSplitList.get(offset + 3)); rectangle = new Envelope(x1, x2, y1, y2); + rectangle.setUserData(line); break; case "geojson": GeoJSONReader reader = new GeoJSONReader(); Geometry result = reader.read(line); rectangle =result.getEnvelopeInternal(); + rectangle.setUserData(line); break; case "wkt": lineSplitList=Arrays.asList(line.split("\t")); WKTReader wtkreader = new WKTReader(); - try { rectangle = wtkreader.read(lineSplitList.get(offset)).getEnvelopeInternal(); - } catch (NullPointerException e) { - rectangle= new Envelope(85.01,86.01,34.01,35.01); - //e.printStackTrace(); - } + rectangle.setUserData(line); break; default: throw new Exception("Input type not recognized, "); diff --git a/src/main/java/org/datasyslab/geospark/geometryObjects/EnvelopeWithGrid.java b/src/main/java/org/datasyslab/geospark/geometryObjects/EnvelopeWithGrid.java index e7de51cb25..a37754824c 100644 --- a/src/main/java/org/datasyslab/geospark/geometryObjects/EnvelopeWithGrid.java +++ b/src/main/java/org/datasyslab/geospark/geometryObjects/EnvelopeWithGrid.java @@ -10,7 +10,7 @@ /** - * The class extends Envelope with one additional id. + * The class extends JTS Envelope with one additional data field * */ public class EnvelopeWithGrid extends Envelope{ diff --git a/src/main/java/org/datasyslab/geospark/geometryObjects/PointWithAttr.java b/src/main/java/org/datasyslab/geospark/geometryObjects/PointWithAttr.java deleted file mode 100644 index f76ff8c8a5..0000000000 --- a/src/main/java/org/datasyslab/geospark/geometryObjects/PointWithAttr.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.datasyslab.geospark.geometryObjects; - -/** - * - * @author Arizona State University DataSystems Lab - * - */ - -import java.io.Serializable; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.geom.PrecisionModel; - -public class PointWithAttr extends Point implements Serializable{ - - public PointWithAttr(Coordinate coordinate, PrecisionModel precisionModel, int SRID) { - super(coordinate, precisionModel, SRID); - // TODO Auto-generated constructor stub - } - - public String headPart; - public String tailPart; - - -} diff --git a/src/main/java/org/datasyslab/geospark/knnJudgement/PointKnnJudgementUsingIndex.java b/src/main/java/org/datasyslab/geospark/knnJudgement/PointKnnJudgementUsingIndex.java index d750fbd274..074f664ec2 100644 --- a/src/main/java/org/datasyslab/geospark/knnJudgement/PointKnnJudgementUsingIndex.java +++ b/src/main/java/org/datasyslab/geospark/knnJudgement/PointKnnJudgementUsingIndex.java @@ -34,13 +34,13 @@ public Iterator call(Iterator t) throws Exception { // TODO Auto-generated method stub GeometryFactory fact= new GeometryFactory(); STRtree strtree = t.next(); - Envelope[] localK = strtree.kNearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), k); + Object[] localK = strtree.kNearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), k); List result = new ArrayList(); for(int i=0;i, Polygon>, Serializable{ + int k; + Point queryCenter; + public PolygonKnnJudgementUsingIndex(Point queryCenter,int k) + { + this.queryCenter=queryCenter; + this.k=k; + } + @Override + public Iterator call(Iterator t) throws Exception { + // TODO Auto-generated method stub + GeometryFactory fact= new GeometryFactory(); + STRtree strtree = t.next(); + Object[] localK = strtree.kNearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), k); + List result = new ArrayList(); + for(int i=0;i call(Iterator t) throws Exception { // TODO Auto-generated method stub GeometryFactory fact= new GeometryFactory(); STRtree strtree = t.next(); - Envelope[] localK = strtree.kNearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), k); - return Arrays.asList(localK).iterator(); + Object[] localK = strtree.kNearestNeighbour(queryCenter.getEnvelopeInternal(), queryCenter, new GeometryItemDistance(), k); + List result = new ArrayList(); + for(int i=0;i call(Iterator t) throws Exception { Iterator initialResultIterator=initialResult.iterator(); while(initialResultIterator.hasNext()) { - result.add(initialResultIterator.next().getEnvelopeInternal()); + Geometry oneResultPoly=(Geometry)initialResultIterator.next(); + Envelope oneResult=oneResultPoly.getEnvelopeInternal(); + oneResult.setUserData(oneResultPoly.getUserData()); + result.add(oneResult); + } return result.iterator(); } diff --git a/src/main/java/org/datasyslab/geospark/spatialOperator/KNNQuery.java b/src/main/java/org/datasyslab/geospark/spatialOperator/KNNQuery.java index c1b27d00f9..2f3ddcaed7 100644 --- a/src/main/java/org/datasyslab/geospark/spatialOperator/KNNQuery.java +++ b/src/main/java/org/datasyslab/geospark/spatialOperator/KNNQuery.java @@ -21,6 +21,7 @@ import org.datasyslab.geospark.knnJudgement.PointKnnJudgementUsingIndex; import org.datasyslab.geospark.knnJudgement.PolygonDistanceComparator; import org.datasyslab.geospark.knnJudgement.PolygonKnnJudgement; +import org.datasyslab.geospark.knnJudgement.PolygonKnnJudgementUsingIndex; import org.datasyslab.geospark.knnJudgement.RectangleDistanceComparator; import org.datasyslab.geospark.knnJudgement.RectangleKnnJudgement; import org.datasyslab.geospark.knnJudgement.RectangleKnnJudgementUsingIndex; @@ -131,5 +132,25 @@ public static List SpatialKnnQuery(PolygonRDD objectRDD, Point queryCen return tmp.takeOrdered(k, new PolygonDistanceComparator(queryCenter)); } - + /** + * Spatial K Nearest Neighbors query using index + * @param objectRDD specify the input rectangelRDD + * @param queryCenter specify the query center + * @param k specify the K + * @return A list which contains K nearest points + */ + public static List SpatialKnnQueryUsingIndex(PolygonRDD objectRDD, Point queryCenter, Integer k) { + // For each partation, build a priority queue that holds the topk + //@SuppressWarnings("serial") + + if(objectRDD.indexedRDDNoId == null) { + throw new NullPointerException("Need to invoke buildIndex() first, indexedRDDNoId is null"); + } + JavaRDD tmp = objectRDD.indexedRDDNoId.mapPartitions(new PolygonKnnJudgementUsingIndex(queryCenter,k)); + + // Take the top k + + return tmp.takeOrdered(k, new PolygonDistanceComparator(queryCenter)); + + } } diff --git a/src/main/java/org/datasyslab/geospark/spatialPartitioning/SpatialPartitioningExecutor.java b/src/main/java/org/datasyslab/geospark/spatialPartitioning/SpatialPartitioningExecutor.java new file mode 100644 index 0000000000..b33537f58c --- /dev/null +++ b/src/main/java/org/datasyslab/geospark/spatialPartitioning/SpatialPartitioningExecutor.java @@ -0,0 +1,11 @@ +package org.datasyslab.geospark.spatialPartitioning; + +public class SpatialPartitioningExecutor { + + int numPartitions; + String gridType; + public SpatialPartitioningExecutor() + { + + } +} diff --git a/src/main/java/org/datasyslab/geospark/spatialRDD/PointRDD.java b/src/main/java/org/datasyslab/geospark/spatialRDD/PointRDD.java index dd8559e2d6..e27684b447 100644 --- a/src/main/java/org/datasyslab/geospark/spatialRDD/PointRDD.java +++ b/src/main/java/org/datasyslab/geospark/spatialRDD/PointRDD.java @@ -108,7 +108,63 @@ public class PointRDD implements Serializable { public PointRDD(JavaRDD rawPointRDD) { this.setRawPointRDD(rawPointRDD); } + + /** + * Transform a rawPointRDD to a PointRDD with a specified spatial partitioning grid type and the number of partitions + * @param rawPointRDD + * @param gridType gridType specify the spatial partitioning method + * @param numPartitions specify the partition number of the SpatialRDD + */ + public PointRDD(JavaRDD rawPointRDD,String gridType, Integer numPartitions) { + this.setRawPointRDD(rawPointRDD); + this.rawPointRDD.persist(StorageLevel.MEMORY_ONLY()); + this.totalNumberOfRecords = this.rawPointRDD.count(); + + doSpatialPartitioning(gridType,numPartitions); + + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridPointRDD = this.rawPointRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Point point) throws Exception { + return PartitionJudgement.getPartitionID(grids,point); + + } + } + ); + this.rawPointRDD.unpersist(); + this.gridPointRDD = unPartitionedGridPointRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + } + + /** + * Transform a rawPointRDD to a PointRDD with a specified spatial partitioning grid type + * @param rawPointRDD + * @param gridType gridType specify the spatial partitioning method + */ + public PointRDD(JavaRDD rawPointRDD,String gridType) { + this.setRawPointRDD(rawPointRDD); + this.rawPointRDD.persist(StorageLevel.MEMORY_ONLY()); + this.totalNumberOfRecords = this.rawPointRDD.count(); + + int numPartitions=this.rawPointRDD.getNumPartitions(); + + doSpatialPartitioning(gridType,numPartitions); + + JavaPairRDD unPartitionedGridPointRDD = this.rawPointRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Point point) throws Exception { + return PartitionJudgement.getPartitionID(grids,point); + + } + } + ); + this.rawPointRDD.unpersist(); + this.gridPointRDD = unPartitionedGridPointRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + } /** * Initialize one raw SpatialRDD with a raw input file @@ -151,62 +207,9 @@ public PointRDD(JavaSparkContext sc, String InputLocation, Integer offset, Strin this.rawPointRDD.persist(StorageLevel.MEMORY_ONLY()); this.totalNumberOfRecords = this.rawPointRDD.count(); - //Calculate the number of samples we need to take. - int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); - - if(sampleNumberOfRecords == -1) { - throw new IllegalArgumentException("The input size is smaller the number of grid, please reduce the grid size!"); - } - //Take Sample - //todo: This creates troubles.. In fact it should be List interface. But List reports problems in Scala Shell, seems that it can not implement polymorphism and Still use List. - ArrayList pointSampleList = new ArrayList(this.rawPointRDD.takeSample(false, sampleNumberOfRecords)); - //Sort - //Get minX and minY; - this.boundary(); - //Pick and create boundary; - + doSpatialPartitioning(gridType,numPartitions); - - //This is the case where data size is too small. We will just create one grid - if(sampleNumberOfRecords == 0) { - //If the sample Number is too small, we will just use one grid instead. - System.err.println("The grid size is " + numPartitions * numPartitions + "for 2-dimension X-Y grid" + numPartitions + " for 1-dimension grid"); - System.err.println("The sample size is " + totalNumberOfRecords/100); - System.err.println("input size is too small, we can not guarantee one grid have at least one record in it"); - System.err.println("we will just build one grid for all input"); - grids = new HashSet(); - grids.add(new EnvelopeWithGrid(this.boundaryEnvelope, 0)); - } else if (gridType.equals("equalgrid")) { - EqualPartitioning equalPartitioning =new EqualPartitioning(this.boundaryEnvelope,numPartitions); - grids=equalPartitioning.getGrids(); - } - else if(gridType.equals("hilbert")) - { - HilbertPartitioning hilbertPartitioning=new HilbertPartitioning(pointSampleList.toArray(new Point[pointSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=hilbertPartitioning.getGrids(); - } - else if(gridType.equals("rtree")) - { - RtreePartitioning rtreePartitioning=new RtreePartitioning(pointSampleList.toArray(new Point[pointSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=rtreePartitioning.getGrids(); - } - else if(gridType.equals("voronoi")) - { - VoronoiPartitioning voronoiPartitioning=new VoronoiPartitioning(pointSampleList.toArray(new Point[pointSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=voronoiPartitioning.getGrids(); - } - else - { - throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); - } - - - - //Note, we don't need cache this RDD in memory, store it in the disk is enough. - //todo, may be refactor this so that user have choice. - //todo, measure this part's time. Using log4j debug level. - //todo, This hashPartitioner could be improved by a simple %, becuase we know they're parition number. - final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); JavaPairRDD unPartitionedGridPointRDD = this.rawPointRDD.flatMapToPair( new PairFlatMapFunction() { @Override @@ -237,6 +240,26 @@ public PointRDD(JavaSparkContext sc, String InputLocation, Integer offset, Strin int numPartitions=this.rawPointRDD.getNumPartitions(); + doSpatialPartitioning(gridType,numPartitions); + + + JavaPairRDD unPartitionedGridPointRDD = this.rawPointRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Point point) throws Exception { + return PartitionJudgement.getPartitionID(grids,point); + + } + } + ); + this.rawPointRDD.unpersist(); + this.gridPointRDD = unPartitionedGridPointRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + + } + + private void doSpatialPartitioning(String gridType, int numPartitions) + { //Calculate the number of samples we need to take. int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); @@ -285,28 +308,8 @@ else if(gridType.equals("voronoi")) { throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); } - - - - //Note, we don't need cache this RDD in memory, store it in the disk is enough. - //todo, may be refactor this so that user have choice. - //todo, measure this part's time. Using log4j debug level. - //todo, This hashPartitioner could be improved by a simple %, becuase we know they're parition number. - //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); - JavaPairRDD unPartitionedGridPointRDD = this.rawPointRDD.flatMapToPair( - new PairFlatMapFunction() { - @Override - public Iterator> call(Point point) throws Exception { - return PartitionJudgement.getPartitionID(grids,point); - - } - } - ); - this.rawPointRDD.unpersist(); - this.gridPointRDD = unPartitionedGridPointRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); - - - } + } + /** * Create an IndexedRDD and cache it in memory. Need to have a grided RDD first. The index is build on each partition. diff --git a/src/main/java/org/datasyslab/geospark/spatialRDD/PolygonRDD.java b/src/main/java/org/datasyslab/geospark/spatialRDD/PolygonRDD.java index e1755f1d8f..6fefdb6f51 100644 --- a/src/main/java/org/datasyslab/geospark/spatialRDD/PolygonRDD.java +++ b/src/main/java/org/datasyslab/geospark/spatialRDD/PolygonRDD.java @@ -160,6 +160,66 @@ public JavaRDD getRawPolygonRDD() { return rawPolygonRDD; } + /** + * Transform a rawRectangleRDD to a RectangelRDD with a a specified spatial partitioning grid type and the number of partitions + * @param rawPolygonRDD + * @param gridType + * @param numPartitions + */ + public PolygonRDD(JavaRDD rawPolygonRDD, String gridType, Integer numPartitions) + { + this.setRawPolygonRDD(rawPolygonRDD.persist(StorageLevel.MEMORY_ONLY())); + this.rawPolygonRDD.persist(StorageLevel.MEMORY_ONLY()); + totalNumberOfRecords = this.rawPolygonRDD.count(); + + doSpatialPartitioning(gridType,numPartitions); + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridPolygonRDD = this.rawPolygonRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Polygon polygon) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,polygon); + return result.iterator(); + } + } + ); + this.rawPolygonRDD.unpersist(); + this.gridPolygonRDD = unPartitionedGridPolygonRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + } + + + /** + * Transform a rawRectangleRDD to a RectangelRDD with a a specified spatial partitioning grid type and the number of partitions + * @param rawPolygonRDD + * @param gridType + */ + public PolygonRDD(JavaRDD rawPolygonRDD, String gridType) + { + this.setRawPolygonRDD(rawPolygonRDD.persist(StorageLevel.MEMORY_ONLY())); + this.rawPolygonRDD.persist(StorageLevel.MEMORY_ONLY()); + totalNumberOfRecords = this.rawPolygonRDD.count(); + int numPartitions=this.rawPolygonRDD.getNumPartitions(); + + doSpatialPartitioning(gridType,numPartitions); + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridPolygonRDD = this.rawPolygonRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Polygon polygon) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,polygon); + return result.iterator(); + } + } + ); + this.rawPolygonRDD.unpersist(); + this.gridPolygonRDD = unPartitionedGridPolygonRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + } + + //todo: remove offset. /** * Initialize one raw SpatialRDD with a raw input file and do spatial partitioning on it @@ -175,43 +235,8 @@ public PolygonRDD(JavaSparkContext sc, String inputLocation, Integer offSet, Str this.rawPolygonRDD.persist(StorageLevel.MEMORY_ONLY()); totalNumberOfRecords = this.rawPolygonRDD.count(); - int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); - - ArrayList polygonSampleList = new ArrayList (rawPolygonRDD.takeSample(false, sampleNumberOfRecords)); - - this.boundary(); + doSpatialPartitioning(gridType,numPartitions); - if(sampleNumberOfRecords == 0) { - //If the sample Number is too small, we will just use one grid instead. - System.err.println("The grid size is " + numPartitions * numPartitions + "for 2-dimension X-Y grid" + numPartitions + " for 1-dimension grid"); - System.err.println("The sample size is " + totalNumberOfRecords /100); - System.err.println("input size is too small, we can not guarantee one grid have at least one record in it"); - System.err.println("we will just build one grid for all input"); - grids = new HashSet(); - grids.add(new EnvelopeWithGrid(this.boundaryEnvelope, 0)); - } else if (gridType.equals("equalgrid")) { - EqualPartitioning equalPartitioning =new EqualPartitioning(this.boundaryEnvelope,numPartitions); - grids=equalPartitioning.getGrids(); - } - else if(gridType.equals("hilbert")) - { - HilbertPartitioning hilbertPartitioning=new HilbertPartitioning(polygonSampleList.toArray(new Polygon[polygonSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=hilbertPartitioning.getGrids(); - } - else if(gridType.equals("rtree")) - { - RtreePartitioning rtreePartitioning=new RtreePartitioning(polygonSampleList.toArray(new Polygon[polygonSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=rtreePartitioning.getGrids(); - } - else if(gridType.equals("voronoi")) - { - VoronoiPartitioning voronoiPartitioning=new VoronoiPartitioning(polygonSampleList.toArray(new Polygon[polygonSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=voronoiPartitioning.getGrids(); - } - else - { - throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); - } //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); JavaPairRDD unPartitionedGridPolygonRDD = this.rawPolygonRDD.flatMapToPair( new PairFlatMapFunction() { @@ -244,6 +269,27 @@ public PolygonRDD(JavaSparkContext sc, String inputLocation, Integer offSet, Str int numPartitions=this.rawPolygonRDD.getNumPartitions(); + doSpatialPartitioning(gridType,numPartitions); + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridPolygonRDD = this.rawPolygonRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Polygon polygon) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,polygon); + return result.iterator(); + } + } + ); + this.rawPolygonRDD.unpersist(); + this.gridPolygonRDD = unPartitionedGridPolygonRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + + + } + + private void doSpatialPartitioning(String gridType, int numPartitions) + { int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); ArrayList polygonSampleList = new ArrayList (rawPolygonRDD.takeSample(false, sampleNumberOfRecords)); @@ -281,22 +327,8 @@ else if(gridType.equals("voronoi")) { throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); } - final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); - JavaPairRDD unPartitionedGridPolygonRDD = this.rawPolygonRDD.flatMapToPair( - new PairFlatMapFunction() { - @Override - public Iterator> call(Polygon polygon) throws Exception { - HashSet> result = PartitionJudgement.getPartitionID(grids,polygon); - return result.iterator(); - } - } - ); - this.rawPolygonRDD.unpersist(); - this.gridPolygonRDD = unPartitionedGridPolygonRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); - - - } + /** * Create an IndexedRDD and cache it in memory. Need to have a grided RDD first. The index is build on each partition. diff --git a/src/main/java/org/datasyslab/geospark/spatialRDD/RectangleRDD.java b/src/main/java/org/datasyslab/geospark/spatialRDD/RectangleRDD.java index 98effa653a..e560eeaf69 100644 --- a/src/main/java/org/datasyslab/geospark/spatialRDD/RectangleRDD.java +++ b/src/main/java/org/datasyslab/geospark/spatialRDD/RectangleRDD.java @@ -147,9 +147,66 @@ public RectangleRDD(JavaSparkContext spark, String InputLocation,Integer Offset, this.setRawRectangleRDD(spark.textFile(InputLocation).map(new RectangleFormatMapper(Offset,Splitter)));//.persist(StorageLevel.MEMORY_AND_DISK_SER())); } + /** + * Transform a rawRectangleRDD to a RectangelRDD with a a specified spatial partitioning grid type + * @param rawRectangleRDD + * @param gridType + */ + public RectangleRDD(JavaRDD rawRectangleRDD, String gridType) + { + this.setRawRectangleRDD(rawRectangleRDD); + this.rawRectangleRDD.persist(StorageLevel.MEMORY_ONLY()); + totalNumberOfRecords = this.rawRectangleRDD.count(); + + int numPartitions=this.rawRectangleRDD.getNumPartitions(); + + doSpatialPartitioning(gridType,numPartitions); + + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridRectangleRDD = this.rawRectangleRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Envelope recntangle) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,recntangle); + return result.iterator(); + } + } + ); + this.rawRectangleRDD.unpersist(); + this.gridRectangleRDD = unPartitionedGridRectangleRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + } - - + /** + * Transform a rawRectangleRDD to a RectangelRDD with a a specified spatial partitioning grid type and the number of partitions + * @param rawRectangleRDD + * @param gridType + * @param numPartitions + */ + public RectangleRDD(JavaRDD rawRectangleRDD, String gridType, Integer numPartitions) + { + this.setRawRectangleRDD(rawRectangleRDD); + this.rawRectangleRDD.persist(StorageLevel.MEMORY_ONLY()); + totalNumberOfRecords = this.rawRectangleRDD.count(); + + + + doSpatialPartitioning(gridType,numPartitions); + + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridRectangleRDD = this.rawRectangleRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Envelope recntangle) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,recntangle); + return result.iterator(); + } + } + ); + this.rawRectangleRDD.unpersist(); + this.gridRectangleRDD = unPartitionedGridRectangleRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + } /** @@ -167,50 +224,10 @@ public RectangleRDD(JavaSparkContext sc, String inputLocation, Integer offSet, S totalNumberOfRecords = this.rawRectangleRDD.count(); - int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); - - ArrayList rectangleSampleList = new ArrayList (rawRectangleRDD.takeSample(false, sampleNumberOfRecords)); - - this.boundary(); - - JavaPairRDD unPartitionedGridPointRDD; - - if(sampleNumberOfRecords == 0) { - //If the sample Number is too small, we will just use one grid instead. - System.err.println("The grid size is " + numPartitions * numPartitions + "for 2-dimension X-Y grid" + numPartitions + " for 1-dimension grid"); - System.err.println("The sample size is " + totalNumberOfRecords /100); - System.err.println("input size is too small, we can not guarantee one grid have at least one record in it"); - System.err.println("we will just build one grid for all input"); - grids = new HashSet(); - grids.add(new EnvelopeWithGrid(this.boundaryEnvelope, 0)); - } - - else if (gridType.equals("equalgrid")) { - EqualPartitioning equalPartitioning =new EqualPartitioning(this.boundaryEnvelope,numPartitions); - grids=equalPartitioning.getGrids(); - } - else if(gridType.equals("hilbert")) - { - HilbertPartitioning hilbertPartitioning=new HilbertPartitioning(rectangleSampleList.toArray(new Envelope[rectangleSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=hilbertPartitioning.getGrids(); - } - else if(gridType.equals("rtree")) - { - RtreePartitioning rtreePartitioning=new RtreePartitioning(rectangleSampleList.toArray(new Envelope[rectangleSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=rtreePartitioning.getGrids(); - } - else if(gridType.equals("voronoi")) - { - VoronoiPartitioning voronoiPartitioning=new VoronoiPartitioning(rectangleSampleList.toArray(new Envelope[rectangleSampleList.size()]),this.boundaryEnvelope,numPartitions); - grids=voronoiPartitioning.getGrids(); - } - else - { - throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); - } + doSpatialPartitioning(gridType,numPartitions); - final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); JavaPairRDD unPartitionedGridRectangleRDD = this.rawRectangleRDD.flatMapToPair( new PairFlatMapFunction() { @Override @@ -240,6 +257,26 @@ public RectangleRDD(JavaSparkContext sc, String inputLocation, Integer offSet, S int numPartitions=this.rawRectangleRDD.getNumPartitions(); + doSpatialPartitioning(gridType,numPartitions); + + //final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); + JavaPairRDD unPartitionedGridRectangleRDD = this.rawRectangleRDD.flatMapToPair( + new PairFlatMapFunction() { + @Override + public Iterator> call(Envelope recntangle) throws Exception { + HashSet> result = PartitionJudgement.getPartitionID(grids,recntangle); + return result.iterator(); + } + } + ); + this.rawRectangleRDD.unpersist(); + this.gridRectangleRDD = unPartitionedGridRectangleRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); + + } + + + private void doSpatialPartitioning(String gridType, int numPartitions) + { int sampleNumberOfRecords = RDDSampleUtils.getSampleNumbers(numPartitions, totalNumberOfRecords); ArrayList rectangleSampleList = new ArrayList (rawRectangleRDD.takeSample(false, sampleNumberOfRecords)); @@ -282,20 +319,6 @@ else if(gridType.equals("voronoi")) throw new IllegalArgumentException("Partitioning method is not recognized, please check again."); } - - final Broadcast> gridEnvelopBroadcasted = sc.broadcast(grids); - JavaPairRDD unPartitionedGridRectangleRDD = this.rawRectangleRDD.flatMapToPair( - new PairFlatMapFunction() { - @Override - public Iterator> call(Envelope recntangle) throws Exception { - HashSet> result = PartitionJudgement.getPartitionID(grids,recntangle); - return result.iterator(); - } - } - ); - this.rawRectangleRDD.unpersist(); - this.gridRectangleRDD = unPartitionedGridRectangleRDD.partitionBy(new SpatialPartitioner(grids.size()));//.persist(StorageLevel.DISK_ONLY()); - } /** @@ -316,7 +339,9 @@ public Iterator call(Iterator t) GeometryFactory geometryFactory = new GeometryFactory(); while(t.hasNext()){ Envelope envelope=t.next(); - rt.insert(envelope, geometryFactory.toGeometry(envelope)); + Geometry item= geometryFactory.toGeometry(envelope); + item.setUserData(envelope.getUserData()); + rt.insert(envelope, item); } HashSet result = new HashSet(); result.add(rt); @@ -351,6 +376,8 @@ public Iterable call(Iterable envelopes) throws Exception { } } + + /** * Get the raw SpatialRDD * diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/PointJoinTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/PointJoinTest.java index 2b37ee5c68..e3521b1b7a 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/PointJoinTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/PointJoinTest.java @@ -95,8 +95,14 @@ public void testSpatialJoinQuery() throws Exception { JoinQuery joinQuery = new JoinQuery(sc,pointRDD,rectangleRDD); List>> result = joinQuery.SpatialJoinQuery(pointRDD,rectangleRDD).collect(); - - System.out.println(result.size()); + assert result.get(1)._1().getUserData()!=null; + for(int i=0;i>> result = joinQuery.SpatialJoinQueryUsingIndex(pointRDD,rectangleRDD).collect(); - - System.out.println(result.size()); + assert result.get(1)._1().getUserData()!=null; + for(int i=0;i result = KNNQuery.SpatialKnnQuery(pointRDD, queryPoint, 5); assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); } - + } @Test public void testSpatialKnnQueryUsingIndex() throws Exception { @@ -109,6 +113,8 @@ public void testSpatialKnnQueryUsingIndex() throws Exception { { List result = KNNQuery.SpatialKnnQueryUsingIndex(pointRDD, queryPoint, 5); assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); } } diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/PointRangeTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/PointRangeTest.java index cc4c22217a..82583bfa56 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/PointRangeTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/PointRangeTest.java @@ -72,7 +72,7 @@ public static void onceExecutedBeforeAll() { splitter = prop.getProperty("splitter"); indexType = prop.getProperty("indexType"); numPartitions = Integer.parseInt(prop.getProperty("numPartitions")); - queryEnvelope=new Envelope (-85.01,-84.01,34.01,35.01); + queryEnvelope=new Envelope (-90.01,-80.01,30.01,40.01); loopTimes=5; } catch (IOException ex) { ex.printStackTrace(); @@ -99,8 +99,10 @@ public void testSpatialRangeQuery() throws Exception { long resultSize = RangeQuery.SpatialRangeQuery(pointRDD, queryEnvelope, 0).getRawPointRDD().count(); assert resultSize>-1; } + assert RangeQuery.SpatialRangeQuery(pointRDD, queryEnvelope, 0).getRawPointRDD().take(10).get(1).getUserData().toString()!=null; } + @Test public void testSpatialRangeQueryUsingIndex() throws Exception { PointRDD pointRDD = new PointRDD(sc, InputLocation, offset, splitter); @@ -110,6 +112,7 @@ public void testSpatialRangeQueryUsingIndex() throws Exception { long resultSize = RangeQuery.SpatialRangeQueryUsingIndex(pointRDD, queryEnvelope, 0).getRawPointRDD().count(); assert resultSize>-1; } + assert RangeQuery.SpatialRangeQueryUsingIndex(pointRDD, queryEnvelope, 0).getRawPointRDD().take(10).get(1).getUserData().toString() !=null; } diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonJoinTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonJoinTest.java index 4c9ea448a5..74fb949dba 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonJoinTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonJoinTest.java @@ -94,8 +94,14 @@ public void testSpatialJoinQuery() throws Exception { JoinQuery joinQuery = new JoinQuery(sc,objectRDD,polygonRDD); List>> result = joinQuery.SpatialJoinQuery(objectRDD,polygonRDD).collect(); - - System.out.println(result.size()); + assert result.get(0)._1().getUserData()!=null; + for(int i=0;i>> result = joinQuery.SpatialJoinQueryUsingIndex(objectRDD,polygonRDD).collect(); - - System.out.println(result.size()); - + assert result.get(0)._1().getUserData()!=null; + for(int i=0;i result = KNNQuery.SpatialKnnQuery(PolygonRDD, queryPoint, 5); + List result = KNNQuery.SpatialKnnQuery(polygonRDD, queryPoint, 5); assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); } } + + @Test + public void testSpatialKnnQueryUsingIndex() throws Exception { + PolygonRDD polygonRDD = new PolygonRDD(sc, InputLocation, offset, splitter); + polygonRDD.buildIndex("rtree"); + for(int i=0;i result = KNNQuery.SpatialKnnQueryUsingIndex(polygonRDD, queryPoint, 5); + assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); + } + } } \ No newline at end of file diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonRangeTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonRangeTest.java index 9e56edffbc..6bd361e17b 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonRangeTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/PolygonRangeTest.java @@ -94,24 +94,24 @@ public static void TearDown() { @Test public void testSpatialRangeQuery() throws Exception { - PolygonRDD PolygonRDD = new PolygonRDD(sc, InputLocation, offset, splitter); + PolygonRDD polygonRDD = new PolygonRDD(sc, InputLocation, offset, splitter); for(int i=0;i-1; } - + assert RangeQuery.SpatialRangeQuery(polygonRDD, queryEnvelope, 0).getRawPolygonRDD().take(10).get(1).getUserData().toString()!=null; } @Test public void testSpatialRangeQueryUsingIndex() throws Exception { - PolygonRDD PolygonRDD = new PolygonRDD(sc, InputLocation, offset, splitter); - PolygonRDD.buildIndex("rtree"); + PolygonRDD polygonRDD = new PolygonRDD(sc, InputLocation, offset, splitter); + polygonRDD.buildIndex("rtree"); for(int i=0;i-1; } - + assert RangeQuery.SpatialRangeQueryUsingIndex(polygonRDD, queryEnvelope, 0).getRawPolygonRDD().take(10).get(1).getUserData().toString()!=null; } } \ No newline at end of file diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleJoinTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleJoinTest.java index 9f8facd9cd..31c723b181 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleJoinTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleJoinTest.java @@ -93,8 +93,14 @@ public void testSpatialJoinQuery() throws Exception { JoinQuery joinQuery = new JoinQuery(sc,objectRDD,rectangleRDD); List>> result = joinQuery.SpatialJoinQuery(objectRDD,rectangleRDD).collect(); - - System.out.println(result.size()); + assert result.get(0)._1().getUserData()!=null; + for(int i=0;i>> result = joinQuery.SpatialJoinQueryUsingIndex(objectRDD,rectangleRDD).collect(); - - System.out.println(result.size()); + assert result.get(0)._1().getUserData()!=null; + for(int i=0;i result = KNNQuery.SpatialKnnQuery(rectangleRDD, queryPoint, 5); assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); } } @@ -111,6 +113,8 @@ public void testSpatialKnnQueryUsingIndex() throws Exception { { List result = KNNQuery.SpatialKnnQueryUsingIndex(rectangleRDD, queryPoint, 5); assert result.size()>-1; + assert result.get(0).getUserData().toString()!=null; + //System.out.println(result.get(0).getUserData().toString()); } } diff --git a/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleRangeTest.java b/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleRangeTest.java index a6d67bbe33..4645cf6e77 100644 --- a/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleRangeTest.java +++ b/src/test/java/org/datasyslab/geospark/spatialOperator/RectangleRangeTest.java @@ -72,7 +72,7 @@ public static void onceExecutedBeforeAll() { splitter = prop.getProperty("splitter"); indexType = prop.getProperty("indexType"); numPartitions = Integer.parseInt(prop.getProperty("numPartitions")); - queryEnvelope=new Envelope (-85.01,-84.01,34.01,35.01); + queryEnvelope=new Envelope (-90.01,-80.01,30.01,40.01); loopTimes=5; } catch (IOException ex) { ex.printStackTrace(); @@ -99,7 +99,7 @@ public void testSpatialRangeQuery() throws Exception { long resultSize = RangeQuery.SpatialRangeQuery(rectangleRDD, queryEnvelope, 0).getRawRectangleRDD().count(); assert resultSize>-1; } - + assert RangeQuery.SpatialRangeQuery(rectangleRDD, queryEnvelope, 0).getRawRectangleRDD().take(10).get(1).getUserData().toString()!=null; } @Test public void testSpatialRangeQueryUsingIndex() throws Exception { @@ -110,7 +110,7 @@ public void testSpatialRangeQueryUsingIndex() throws Exception { long resultSize = RangeQuery.SpatialRangeQueryUsingIndex(rectangleRDD, queryEnvelope, 0).getRawRectangleRDD().count(); assert resultSize>-1; } - + assert RangeQuery.SpatialRangeQueryUsingIndex(rectangleRDD, queryEnvelope, 0).getRawRectangleRDD().take(10).get(1).getUserData().toString()!=null; } } \ No newline at end of file